// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers // // This file is part of Bytecoin. // // Bytecoin is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Bytecoin is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with Bytecoin. If not, see . #include "gtest/gtest.h" #include #include "EventWaiter.h" #include "ICoreStub.h" #include "ICryptonoteProtocolQueryStub.h" #include "inprocess_node/InProcessNode.h" struct CallbackStatus { CallbackStatus() {} bool wait() { return waiter.wait_for(std::chrono::milliseconds(3000)); } bool ok() { return waiter.wait_for(std::chrono::milliseconds(3000)) && !static_cast(code); } void setStatus(const std::error_code& ec) { code = ec; waiter.notify(); } std::error_code getStatus() const { return code; } std::error_code code; EventWaiter waiter; }; class InProcessNode : public ::testing::Test { public: InProcessNode() : node(coreStub, protocolQueryStub) {} void SetUp(); protected: void initNode(); ICoreStub coreStub; ICryptonoteProtocolQueryStub protocolQueryStub; CryptoNote::InProcessNode node; }; void InProcessNode::SetUp() { initNode(); } void InProcessNode::initNode() { CallbackStatus status; node.init([&status] (std::error_code ec) { status.setStatus(ec); }); ASSERT_TRUE(status.ok()); } TEST_F(InProcessNode, initOk) { CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub); CallbackStatus status; newNode.init([&status] (std::error_code ec) { status.setStatus(ec); }); ASSERT_TRUE(status.ok()); } TEST_F(InProcessNode, doubleInit) { CallbackStatus status; node.init([&status] (std::error_code ec) { status.setStatus(ec); }); ASSERT_TRUE(status.wait()); std::error_code ec = status.getStatus(); ASSERT_NE(ec, std::error_code()); } TEST_F(InProcessNode, shutdownNotInited) { CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub); ASSERT_FALSE(newNode.shutdown()); } TEST_F(InProcessNode, shutdown) { ASSERT_TRUE(node.shutdown()); } TEST_F(InProcessNode, getPeersCountSuccess) { protocolQueryStub.setPeerCount(1); ASSERT_EQ(1, node.getPeerCount()); } TEST_F(InProcessNode, getLastLocalBlockHeightSuccess) { crypto::hash ignore; coreStub.set_blockchain_top(10, ignore, true); ASSERT_EQ(10, node.getLastLocalBlockHeight()); } TEST_F(InProcessNode, getLastLocalBlockHeightFailure) { crypto::hash ignore; coreStub.set_blockchain_top(10, ignore, false); ASSERT_ANY_THROW(node.getLastLocalBlockHeight()); } TEST_F(InProcessNode, getLastKnownBlockHeightSuccess) { protocolQueryStub.setObservedHeight(10); ASSERT_EQ(10, node.getLastKnownBlockHeight()); } TEST_F(InProcessNode, getTransactionOutsGlobalIndicesSuccess) { crypto::hash ignore; std::vector indices; std::vector expectedIndices; uint64_t start = 10; std::generate_n(std::back_inserter(expectedIndices), 5, [&start] () { return start++; }); coreStub.set_outputs_gindexs(expectedIndices, true); CallbackStatus status; node.getTransactionOutsGlobalIndices(ignore, indices, [&status] (std::error_code ec) { status.setStatus(ec); }); ASSERT_TRUE(status.ok()); ASSERT_EQ(expectedIndices.size(), indices.size()); std::sort(indices.begin(), indices.end()); ASSERT_TRUE(std::equal(indices.begin(), indices.end(), expectedIndices.begin())); } TEST_F(InProcessNode, getTransactionOutsGlobalIndicesFailure) { crypto::hash ignore; std::vector indices; coreStub.set_outputs_gindexs(indices, false); CallbackStatus status; node.getTransactionOutsGlobalIndices(ignore, indices, [&status] (std::error_code ec) { status.setStatus(ec); }); ASSERT_TRUE(status.wait()); ASSERT_NE(std::error_code(), status.getStatus()); } TEST_F(InProcessNode, getRandomOutsByAmountsSuccess) { crypto::public_key ignoredPublicKey; crypto::secret_key ignoredSectetKey; crypto::generate_keys(ignoredPublicKey, ignoredSectetKey); cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response expectedResp; cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_outs_for_amount out; out.amount = 10; out.outs.push_back({ 11, ignoredPublicKey }); expectedResp.outs.push_back(out); coreStub.set_random_outs(expectedResp, true); std::vector outs; CallbackStatus status; node.getRandomOutsByAmounts({1,2,3}, 1, outs, [&status] (std::error_code ec) { status.setStatus(ec); }); ASSERT_TRUE(status.ok()); ASSERT_EQ(1, outs.size()); ASSERT_EQ(10, outs[0].amount); ASSERT_EQ(1, outs[0].outs.size()); ASSERT_EQ(11, outs[0].outs.front().global_amount_index); } TEST_F(InProcessNode, getRandomOutsByAmountsFailure) { cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response expectedResp; coreStub.set_random_outs(expectedResp, false); std::vector outs; CallbackStatus status; node.getRandomOutsByAmounts({1,2,3}, 1, outs, [&status] (std::error_code ec) { status.setStatus(ec); }); ASSERT_TRUE(status.wait()); ASSERT_NE(std::error_code(), status.getStatus()); } TEST_F(InProcessNode, getPeerCountUninitialized) { CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub); ASSERT_ANY_THROW(newNode.getPeerCount()); } TEST_F(InProcessNode, getLastLocalBlockHeightUninitialized) { CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub); ASSERT_ANY_THROW(newNode.getLastLocalBlockHeight()); } TEST_F(InProcessNode, getLastKnownBlockHeightUninitialized) { CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub); ASSERT_ANY_THROW(newNode.getLastKnownBlockHeight()); } TEST_F(InProcessNode, getNewBlocksUninitialized) { CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub); std::list knownBlockIds; std::list newBlocks; uint64_t startHeight; CallbackStatus status; newNode.getNewBlocks(std::move(knownBlockIds), newBlocks, startHeight, [&] (std::error_code ec) { status.setStatus(ec); }); ASSERT_TRUE(status.wait()); ASSERT_NE(std::error_code(), status.getStatus()); } TEST_F(InProcessNode, getTransactionOutsGlobalIndicesUninitialized) { CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub); std::vector outsGlobalIndices; CallbackStatus status; newNode.getTransactionOutsGlobalIndices(crypto::hash(), outsGlobalIndices, [&] (std::error_code ec) { status.setStatus(ec); }); ASSERT_TRUE(status.wait()); ASSERT_NE(std::error_code(), status.getStatus()); } TEST_F(InProcessNode, getRandomOutsByAmountsUninitialized) { CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub); std::vector outs; CallbackStatus status; newNode.getRandomOutsByAmounts({1,2,3}, 1, outs, [&] (std::error_code ec) { status.setStatus(ec); }); ASSERT_TRUE(status.wait()); ASSERT_NE(std::error_code(), status.getStatus()); } TEST_F(InProcessNode, relayTransactionUninitialized) { CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub); CallbackStatus status; newNode.relayTransaction(cryptonote::Transaction(), [&] (std::error_code ec) { status.setStatus(ec); }); ASSERT_TRUE(status.wait()); ASSERT_NE(std::error_code(), status.getStatus()); } TEST_F(InProcessNode, getLastLocalBlockTimestamp) { class GetBlockTimestampCore : public ICoreStub { public: GetBlockTimestampCore(uint64_t timestamp) : timestamp(timestamp) {} virtual bool get_blockchain_top(uint64_t& height, crypto::hash& top_id) override { return true; } virtual bool getBlockByHash(const crypto::hash &h, cryptonote::Block &blk) override { blk.timestamp = timestamp; return true; } uint64_t timestamp; }; uint64_t expectedTimestamp = 1234567890; GetBlockTimestampCore core(expectedTimestamp); CryptoNote::InProcessNode newNode(core, protocolQueryStub); CallbackStatus initStatus; newNode.init([&initStatus] (std::error_code ec) { initStatus.setStatus(ec); }); ASSERT_TRUE(initStatus.wait()); uint64_t timestamp = newNode.getLastLocalBlockTimestamp(); ASSERT_EQ(expectedTimestamp, timestamp); } TEST_F(InProcessNode, getLastLocalBlockTimestampError) { class GetBlockTimestampErrorCore : public ICoreStub { public: virtual bool get_blockchain_top(uint64_t& height, crypto::hash& top_id) override { return true; } virtual bool getBlockByHash(const crypto::hash &h, cryptonote::Block &blk) override { return false; } }; GetBlockTimestampErrorCore core; CryptoNote::InProcessNode newNode(core, protocolQueryStub); CallbackStatus initStatus; newNode.init([&initStatus] (std::error_code ec) { initStatus.setStatus(ec); }); ASSERT_TRUE(initStatus.wait()); ASSERT_THROW(newNode.getLastLocalBlockTimestamp(), std::exception); } //TODO: make relayTransaction unit test //TODO: make getNewBlocks unit test //TODO: make queryBlocks unit test