Skip to content

Commit

Permalink
Use fixture templates to allow running same tests on different implem…
Browse files Browse the repository at this point in the history
…entations (#1080)

Currently we are using the "old" bitcoin validation functions, wrapped in the `LegacyValidationInterface`, as introduced when finally removing Proof-of-Work in #929. In that pull request we hid the existing validation functions behind an interface so we could swap out the legacy function against the new ones from `staking::BlockValidator` - featuring the same interface.

Ultimately we want to use the new `staking::BlockValidator` which is not in use currently. In order to verify that a second implementation of the `LegacyValidationInterface` which will delegate to `staking::BlockValidator` does the same validations as the existing functions it would be nice to have a way of running the same unit test suite against different instances of it.

This pull request uses `BOOST_AUTO_TEST_CASE_TEMPLATE` to achieve exactly that. It is extracted from #939.

[`BOOST_AUTO_TEST_CASE_TEMPLATE`](https://www.boost.org/doc/libs/1_46_0/libs/test/doc/html/utf/user-guide/test-organization/auto-test-case-template.html) will allow to check both implementations of `LegacyValidationInterface` (introduced in #929) to do the right thing. This way the same test tests the two, since they are providing the same interface.

The new implementation of LegacyValidationInterface will land in a separate pull request. Thus the tests currently only operate on one fixture. One can add arbitrary number of Fixtures to the `TestFixtures` type which is a [boost mpl list](https://www.boost.org/doc/libs/1_63_0/libs/mpl/doc/index.html).

Signed-off-by: Julian Fleischer <julian@thirdhash.com>
  • Loading branch information
scravy authored May 8, 2019
1 parent 1e2a39c commit 9978e63
Showing 1 changed file with 69 additions and 34 deletions.
103 changes: 69 additions & 34 deletions src/test/validation_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
#include <keystore.h>
#include <script/interpreter.h>
#include <staking/legacy_validation_interface.h>
#include <test/test_unite.h>
#include <validation.h>

#include <test/test_unite.h>
#include <test/test_unite_mocks.h>

#include <boost/mpl/list.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>

namespace {
Expand All @@ -20,6 +24,23 @@ void SortTxs(CBlock &block, bool reverse = false) {
std::reverse(block.vtx.begin() + 1, block.vtx.end());
}
}
struct Fixture {
std::unique_ptr<blockchain::Behavior> blockchain_behavior =
blockchain::Behavior::NewForNetwork(blockchain::Network::test);
mocks::ActiveChainMock active_chain;
std::unique_ptr<staking::BlockValidator> block_validator =
staking::BlockValidator::New(blockchain_behavior.get());
mocks::StakeValidatorMock stake_validator;
std::unique_ptr<staking::LegacyValidationInterface> validation;

explicit Fixture(decltype(&staking::LegacyValidationInterface::LegacyImpl) factory)
: validation(factory(&active_chain, block_validator.get(), &stake_validator)) {}
};
struct LegacyImpl : public Fixture {
LegacyImpl() : Fixture(staking::LegacyValidationInterface::LegacyImpl) {}
};
using TestFixtures = boost::mpl::list<LegacyImpl>;

} // namespace

BOOST_FIXTURE_TEST_SUITE(validation_tests, TestingSetup)
Expand Down Expand Up @@ -70,18 +91,20 @@ CMutableTransaction CreateCoinbase() {
return coinbase_tx;
}

BOOST_AUTO_TEST_CASE(checkblock_empty) {
BOOST_AUTO_TEST_CASE_TEMPLATE(checkblock_empty, F, TestFixtures) {
F fixture;

CBlock block;
assert(block.vtx.empty());

CValidationState state;
staking::LegacyValidationInterface::Old()->CheckBlock(block, state, Params().GetConsensus(), false, false);
fixture.validation->CheckBlock(block, state, Params().GetConsensus(), false, false);

BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-blk-length");
}

BOOST_AUTO_TEST_CASE(checkblock_too_many_transactions) {
BOOST_AUTO_TEST_CASE_TEMPLATE(checkblock_too_many_transactions, F, TestFixtures) {
F fixture;

auto tx_weight = GetTransactionWeight(CTransaction(CreateTx()));

Expand All @@ -91,36 +114,39 @@ BOOST_AUTO_TEST_CASE(checkblock_too_many_transactions) {
}

CValidationState state;
staking::LegacyValidationInterface::Old()->CheckBlock(block, state, Params().GetConsensus(), false, false);
fixture.validation->CheckBlock(block, state, Params().GetConsensus(), false, false);

BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-blk-length");
}

BOOST_AUTO_TEST_CASE(checkblock_coinbase_missing) {
BOOST_AUTO_TEST_CASE_TEMPLATE(checkblock_coinbase_missing, F, TestFixtures) {
F fixture;

CBlock block;
block.vtx.push_back(MakeTransactionRef(CTransaction(CreateTx())));

CValidationState state;
staking::LegacyValidationInterface::Old()->CheckBlock(block, state, Params().GetConsensus(), false, false);
fixture.validation->CheckBlock(block, state, Params().GetConsensus(), false, false);

BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-cb-missing");
}

BOOST_AUTO_TEST_CASE(checkblock_duplicate_coinbase) {
BOOST_AUTO_TEST_CASE_TEMPLATE(checkblock_duplicate_coinbase, F, TestFixtures) {
F fixture;

CBlock block;
block.vtx.push_back(MakeTransactionRef(CreateCoinbase()));
block.vtx.push_back(MakeTransactionRef(CTransaction(CreateTx())));
block.vtx.push_back(MakeTransactionRef(CreateCoinbase()));

CValidationState state;
staking::LegacyValidationInterface::Old()->CheckBlock(block, state, Params().GetConsensus(), false, false);
fixture.validation->CheckBlock(block, state, Params().GetConsensus(), false, false);

BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-cb-multiple");
}

BOOST_AUTO_TEST_CASE(checkblock_too_many_sigs) {
BOOST_AUTO_TEST_CASE_TEMPLATE(checkblock_too_many_sigs, F, TestFixtures) {
F fixture;

CBlock block;
block.vtx.push_back(MakeTransactionRef(CreateCoinbase()));
Expand All @@ -135,24 +161,27 @@ BOOST_AUTO_TEST_CASE(checkblock_too_many_sigs) {
block.vtx.push_back(MakeTransactionRef(CTransaction(tx)));

CValidationState state;
staking::LegacyValidationInterface::Old()->CheckBlock(block, state, Params().GetConsensus(), false, false);
fixture.validation->CheckBlock(block, state, Params().GetConsensus(), false, false);

BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-blk-sigops");
}

BOOST_AUTO_TEST_CASE(checkblock_merkle_root) {
BOOST_AUTO_TEST_CASE_TEMPLATE(checkblock_merkle_root, F, TestFixtures) {
F fixture;

CBlock block;
block.vtx.push_back(MakeTransactionRef(CreateCoinbase()));

block.hashMerkleRoot = GetRandHash();

CValidationState state;
staking::LegacyValidationInterface::Old()->CheckBlock(block, state, Params().GetConsensus(), false, true);
fixture.validation->CheckBlock(block, state, Params().GetConsensus(), false, true);

BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txnmrklroot");
}

BOOST_AUTO_TEST_CASE(checkblock_merkle_root_mutated) {
BOOST_AUTO_TEST_CASE_TEMPLATE(checkblock_merkle_root_mutated, F, TestFixtures) {
F fixture;

CBlock block;
block.vtx.push_back(MakeTransactionRef(CreateCoinbase()));
Expand All @@ -165,12 +194,13 @@ BOOST_AUTO_TEST_CASE(checkblock_merkle_root_mutated) {
block.hashMerkleRoot = BlockMerkleRoot(block, &ignored);

CValidationState state;
staking::LegacyValidationInterface::Old()->CheckBlock(block, state, Params().GetConsensus(), false, true);
fixture.validation->CheckBlock(block, state, Params().GetConsensus(), false, true);

BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-duplicate");
}

BOOST_AUTO_TEST_CASE(checkblock_duplicates_tx) {
BOOST_AUTO_TEST_CASE_TEMPLATE(checkblock_duplicates_tx, F, TestFixtures) {
F fixture;

CBlockIndex prev;
CBlock block;
Expand All @@ -181,12 +211,13 @@ BOOST_AUTO_TEST_CASE(checkblock_duplicates_tx) {
block.vtx.push_back(MakeTransactionRef(tx));

CValidationState state;
staking::LegacyValidationInterface::Old()->CheckBlock(block, state, Params().GetConsensus(), false, false);
fixture.validation->CheckBlock(block, state, Params().GetConsensus(), false, false);

BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-duplicate");
}

BOOST_AUTO_TEST_CASE(checkblock_tx_order) {
BOOST_AUTO_TEST_CASE_TEMPLATE(checkblock_tx_order, F, TestFixtures) {
F fixture;

CBlockIndex prev;
CBlock block;
Expand All @@ -196,17 +227,18 @@ BOOST_AUTO_TEST_CASE(checkblock_tx_order) {
SortTxs(block, true);

CValidationState state;
staking::LegacyValidationInterface::Old()->CheckBlock(block, state, Params().GetConsensus(), false, false);
fixture.validation->CheckBlock(block, state, Params().GetConsensus(), false, false);

BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-tx-ordering");
}

BOOST_AUTO_TEST_CASE(contextualcheckblock_is_final_tx) {
BOOST_AUTO_TEST_CASE_TEMPLATE(contextualcheckblock_is_final_tx, F, TestFixtures) {
F fixture;

CBlockIndex prev;
prev.nTime = 100000;
prev.nHeight = 10;

CMutableTransaction final_tx = CreateTx();
final_tx.nLockTime = 0;
final_tx.vin.resize(1);
Expand All @@ -225,7 +257,7 @@ BOOST_AUTO_TEST_CASE(contextualcheckblock_is_final_tx) {
SortTxs(block);

CValidationState state;
staking::LegacyValidationInterface::Old()->ContextualCheckBlock(block, state, Params().GetConsensus(), &prev);
fixture.validation->ContextualCheckBlock(block, state, Params().GetConsensus(), &prev);

BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-nonfinal");
}
Expand All @@ -243,13 +275,14 @@ BOOST_AUTO_TEST_CASE(contextualcheckblock_is_final_tx) {
SortTxs(block);

CValidationState state;
staking::LegacyValidationInterface::Old()->ContextualCheckBlock(block, state, Params().GetConsensus(), &prev);
fixture.validation->ContextualCheckBlock(block, state, Params().GetConsensus(), &prev);

BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-nonfinal");
}
}

BOOST_AUTO_TEST_CASE(checkblock_witness) {
BOOST_AUTO_TEST_CASE_TEMPLATE(checkblock_witness, F, TestFixtures) {
F fixture;

CBlockIndex prev;

Expand All @@ -262,12 +295,13 @@ BOOST_AUTO_TEST_CASE(checkblock_witness) {
block.hash_witness_merkle_root = GetRandHash();

CValidationState state;
staking::LegacyValidationInterface::Old()->CheckBlock(block, state, consensus_params, false, true);
fixture.validation->CheckBlock(block, state, consensus_params, false, true);

BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-witness-merkle-match");
}

BOOST_AUTO_TEST_CASE(contextualcheckblock_block_weight) {
BOOST_AUTO_TEST_CASE_TEMPLATE(contextualcheckblock_block_weight, F, TestFixtures) {
F fixture;

CBlockIndex prev;
CBlock block;
Expand All @@ -278,12 +312,13 @@ BOOST_AUTO_TEST_CASE(contextualcheckblock_block_weight) {
SortTxs(block);

CValidationState state;
staking::LegacyValidationInterface::Old()->ContextualCheckBlock(block, state, Params().GetConsensus(), &prev);
fixture.validation->ContextualCheckBlock(block, state, Params().GetConsensus(), &prev);

BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-blk-weight");
}

BOOST_AUTO_TEST_CASE(contextualcheckblockheader_time) {
BOOST_AUTO_TEST_CASE_TEMPLATE(contextualcheckblockheader_time, F, TestFixtures) {
F fixture;

// Block time is too far in the past
int64_t adjusted_time = 151230;
Expand All @@ -301,15 +336,15 @@ BOOST_AUTO_TEST_CASE(contextualcheckblockheader_time) {
prev_2.pprev = &prev_1;

CBlock block;
block.nTime = 2001; // 1 unit more than the median
block.nTime = 2001; // 1 unit more than the median

prev_2.phashBlock = &block.hashPrevBlock;

CValidationState state;
BOOST_CHECK(staking::LegacyValidationInterface::Old()->ContextualCheckBlockHeader(block, state, Params(), &prev_2, adjusted_time));
BOOST_CHECK(fixture.validation->ContextualCheckBlockHeader(block, state, Params(), &prev_2, adjusted_time));

block.nTime = 1999; // 1 unit less than the median
staking::LegacyValidationInterface::Old()->ContextualCheckBlockHeader(block, state, Params(), &prev_2, adjusted_time);
block.nTime = 1999; // 1 unit less than the median
fixture.validation->ContextualCheckBlockHeader(block, state, Params(), &prev_2, adjusted_time);
BOOST_CHECK_EQUAL(state.GetRejectReason(), "time-too-old");
}

Expand All @@ -325,10 +360,10 @@ BOOST_AUTO_TEST_CASE(contextualcheckblockheader_time) {
prev.phashBlock = &block.hashPrevBlock;

CValidationState state;
BOOST_CHECK(staking::LegacyValidationInterface::Old()->ContextualCheckBlockHeader(block, state, Params(), &prev, adjusted_time));
BOOST_CHECK(fixture.validation->ContextualCheckBlockHeader(block, state, Params(), &prev, adjusted_time));

block.nTime = adjusted_time + params.max_future_block_time_seconds + 1;
staking::LegacyValidationInterface::Old()->ContextualCheckBlockHeader(block, state, Params(), &prev, adjusted_time);
fixture.validation->ContextualCheckBlockHeader(block, state, Params(), &prev, adjusted_time);
BOOST_CHECK_EQUAL(state.GetRejectReason(), "time-too-new");
}
}
Expand Down

0 comments on commit 9978e63

Please sign in to comment.