Problem: Need tests to verify that the unified conclusion for ValidatorElection and MigrationElection works when both election types conclude in the same block

Solution: Wrote some integration tests
This commit is contained in:
z-bowen 2018-09-13 22:46:49 +02:00
parent 9942867e47
commit cc0ce0e5e4
7 changed files with 210 additions and 71 deletions

View File

@ -20,15 +20,17 @@ from logging.config import dictConfig
import pytest import pytest
from pymongo import MongoClient from pymongo import MongoClient
from bigchaindb import ValidatorElection
from bigchaindb.common import crypto from bigchaindb.common import crypto
from bigchaindb.log import setup_logging from bigchaindb.log import setup_logging
from bigchaindb.migrations.migration_election import MigrationElection
from bigchaindb.tendermint_utils import key_from_base64 from bigchaindb.tendermint_utils import key_from_base64
from bigchaindb.backend import schema from bigchaindb.backend import schema, query
from bigchaindb.common.crypto import (key_pair_from_ed25519_key, from bigchaindb.common.crypto import (key_pair_from_ed25519_key,
public_key_from_ed25519_key) public_key_from_ed25519_key)
from bigchaindb.common.exceptions import DatabaseDoesNotExist from bigchaindb.common.exceptions import DatabaseDoesNotExist
from bigchaindb.lib import Block from bigchaindb.lib import Block
from tests.utils import gen_vote
TEST_DB_NAME = 'bigchain_test' TEST_DB_NAME = 'bigchain_test'
@ -694,3 +696,117 @@ def new_validator():
'type': 'ed25519-base16'}, 'type': 'ed25519-base16'},
'power': power, 'power': power,
'node_id': node_id} 'node_id': node_id}
@pytest.fixture
def valid_upsert_validator_election(b_mock, node_key, new_validator):
voters = ValidatorElection.recipients(b_mock)
return ValidatorElection.generate([node_key.public_key],
voters,
new_validator, None).sign([node_key.private_key])
@pytest.fixture
def valid_upsert_validator_election_2(b_mock, node_key, new_validator):
voters = ValidatorElection.recipients(b_mock)
return ValidatorElection.generate([node_key.public_key],
voters,
new_validator, None).sign([node_key.private_key])
@pytest.fixture
def valid_migration_election(b_mock, node_key):
voters = MigrationElection.recipients(b_mock)
return MigrationElection.generate([node_key.public_key],
voters,
{}, None).sign([node_key.private_key])
@pytest.fixture
def valid_migration_election_2(b_mock, node_key):
voters = MigrationElection.recipients(b_mock)
return MigrationElection.generate([node_key.public_key],
voters,
{}, None).sign([node_key.private_key])
@pytest.fixture
def ongoing_validator_election(b, valid_upsert_validator_election, ed25519_node_keys):
validators = b.get_validators(height=1)
genesis_validators = {'validators': validators,
'height': 0,
'election_id': None}
query.store_validator_set(b.connection, genesis_validators)
b.store_bulk_transactions([valid_upsert_validator_election])
block_1 = Block(app_hash='hash_1', height=1, transactions=[valid_upsert_validator_election.id])
b.store_block(block_1._asdict())
return valid_upsert_validator_election
@pytest.fixture
def ongoing_validator_election_2(b, valid_upsert_validator_election_2, ed25519_node_keys):
validators = b.get_validators(height=1)
genesis_validators = {'validators': validators,
'height': 0,
'election_id': None}
query.store_validator_set(b.connection, genesis_validators)
b.store_bulk_transactions([valid_upsert_validator_election_2])
block_1 = Block(app_hash='hash_2', height=1, transactions=[valid_upsert_validator_election_2.id])
b.store_block(block_1._asdict())
return valid_upsert_validator_election_2
@pytest.fixture
def ongoing_migration_election(b, valid_migration_election, ed25519_node_keys):
b.store_bulk_transactions([valid_migration_election])
block_1 = Block(app_hash='hash_1', height=1, transactions=[valid_migration_election.id])
b.store_block(block_1._asdict())
return valid_migration_election
@pytest.fixture
def ongoing_migration_election_2(b, valid_migration_election_2, ed25519_node_keys):
b.store_bulk_transactions([valid_migration_election_2])
block_1 = Block(app_hash='hash_2', height=1, transactions=[valid_migration_election_2.id])
b.store_block(block_1._asdict())
return valid_migration_election_2
@pytest.fixture
def validator_election_votes(b_mock, ongoing_validator_election, ed25519_node_keys):
voters = ValidatorElection.recipients(b_mock)
votes = generate_votes(ongoing_validator_election, voters, ed25519_node_keys)
return votes
@pytest.fixture
def validator_election_votes_2(b_mock, ongoing_validator_election_2, ed25519_node_keys):
voters = ValidatorElection.recipients(b_mock)
votes = generate_votes(ongoing_validator_election_2, voters, ed25519_node_keys)
return votes
@pytest.fixture
def migration_election_votes(b_mock, ongoing_migration_election, ed25519_node_keys):
voters = MigrationElection.recipients(b_mock)
votes = generate_votes(ongoing_migration_election, voters, ed25519_node_keys)
return votes
@pytest.fixture
def migration_election_votes_2(b_mock, ongoing_migration_election_2, ed25519_node_keys):
voters = MigrationElection.recipients(b_mock)
votes = generate_votes(ongoing_migration_election_2, voters, ed25519_node_keys)
return votes
def generate_votes(election, voters, keys):
votes = []
for voter in range(len(voters)):
v = gen_vote(election, voter, keys)
votes.append(v)
return votes

View File

View File

@ -0,0 +1,60 @@
from unittest.mock import MagicMock
import pytest
from bigchaindb.elections.election import Election
@pytest.mark.bdb
def test_approved_elections_one_migration_one_upsert(b,
ongoing_validator_election, validator_election_votes,
ongoing_migration_election, migration_election_votes):
txns = validator_election_votes + \
migration_election_votes
mock_chain_migration, mock_store_validator = run_approved_elections(b, txns)
mock_chain_migration.assert_called_once()
mock_store_validator.assert_called_once()
@pytest.mark.bdb
def test_approved_elections_two_migrations_two_upsert(b,
ongoing_validator_election, validator_election_votes,
ongoing_validator_election_2, validator_election_votes_2,
ongoing_migration_election, migration_election_votes,
ongoing_migration_election_2, migration_election_votes_2):
txns = validator_election_votes + \
validator_election_votes_2 + \
migration_election_votes + \
migration_election_votes_2
mock_chain_migration, mock_store_validator = run_approved_elections(b, txns)
mock_chain_migration.assert_called_once()
mock_store_validator.assert_called_once()
@pytest.mark.bdb
def test_approved_elections_two_migrations_one_upsert(b,
ongoing_validator_election, validator_election_votes,
ongoing_migration_election, migration_election_votes,
ongoing_migration_election_2, migration_election_votes_2):
txns = validator_election_votes + \
migration_election_votes + \
migration_election_votes_2
mock_chain_migration, mock_store_validator = run_approved_elections(b, txns)
mock_chain_migration.assert_called_once()
mock_store_validator.assert_called_once()
def test_approved_elections_no_elections(b):
txns = []
mock_chain_migration, mock_store_validator = run_approved_elections(b, txns)
mock_chain_migration.assert_not_called()
mock_store_validator.assert_not_called()
def run_approved_elections(bigchain, txns):
mock_chain_migration = MagicMock()
mock_store_validator = MagicMock()
bigchain.migrate_abci_chain = mock_chain_migration
bigchain.store_validator_set = mock_store_validator
Election.approved_elections(bigchain, 1, txns)
return mock_chain_migration, mock_store_validator

View File

@ -5,20 +5,10 @@ from unittest.mock import patch
import pytest import pytest
from bigchaindb import Vote
from bigchaindb.backend.localmongodb import query from bigchaindb.backend.localmongodb import query
from bigchaindb.lib import Block
from bigchaindb.upsert_validator import ValidatorElection from bigchaindb.upsert_validator import ValidatorElection
@pytest.fixture
def valid_upsert_validator_election(b_mock, node_key, new_validator):
voters = ValidatorElection.recipients(b_mock)
return ValidatorElection.generate([node_key.public_key],
voters,
new_validator, None).sign([node_key.private_key])
@pytest.fixture @pytest.fixture
def valid_upsert_validator_election_b(b, node_key, new_validator): def valid_upsert_validator_election_b(b, node_key, new_validator):
voters = ValidatorElection.recipients(b) voters = ValidatorElection.recipients(b)
@ -37,30 +27,16 @@ def fixed_seed_election(b_mock, node_key, new_validator):
@pytest.fixture @pytest.fixture
def ongoing_election(b, valid_upsert_validator_election, ed25519_node_keys): def concluded_election(b, ongoing_validator_election, ed25519_node_keys):
validators = b.get_validators(height=1)
genesis_validators = {'validators': validators,
'height': 0,
'election_id': None}
query.store_validator_set(b.connection, genesis_validators)
b.store_bulk_transactions([valid_upsert_validator_election])
block_1 = Block(app_hash='hash_1', height=1, transactions=[valid_upsert_validator_election.id])
b.store_block(block_1._asdict())
return valid_upsert_validator_election
@pytest.fixture
def concluded_election(b, ongoing_election, ed25519_node_keys):
election_result = {'height': 2, election_result = {'height': 2,
'election_id': ongoing_election.id} 'election_id': ongoing_validator_election.id}
query.store_election_results(b.connection, election_result) query.store_election_results(b.connection, election_result)
return ongoing_election return ongoing_validator_election
@pytest.fixture @pytest.fixture
def inconclusive_election(b, ongoing_election, new_validator): def inconclusive_election(b, ongoing_validator_election, new_validator):
validators = b.get_validators(height=1) validators = b.get_validators(height=1)
validators[0]['voting_power'] = 15 validators[0]['voting_power'] = 15
validator_update = {'validators': validators, validator_update = {'validators': validators,
@ -68,20 +44,4 @@ def inconclusive_election(b, ongoing_election, new_validator):
'election_id': 'some_other_election'} 'election_id': 'some_other_election'}
query.store_validator_set(b.connection, validator_update) query.store_validator_set(b.connection, validator_update)
return ongoing_election return ongoing_validator_election
def vote(election, voter, keys, b):
election_input = election.to_inputs()[voter]
votes = election.outputs[voter].amount
public_key = election_input.owners_before[0]
key = keys[public_key]
election_pub_key = ValidatorElection.to_public_key(election.id)
v = Vote.generate([election_input],
[([election_pub_key], votes)],
election_id=election.id)\
.sign([key.private_key])
b.store_bulk_transactions([v])
return v

View File

@ -12,7 +12,7 @@ from bigchaindb.common.exceptions import AmountError
from bigchaindb.common.crypto import generate_key_pair from bigchaindb.common.crypto import generate_key_pair
from bigchaindb.common.exceptions import ValidationError from bigchaindb.common.exceptions import ValidationError
from bigchaindb.elections.vote import Vote from bigchaindb.elections.vote import Vote
from tests.utils import generate_block from tests.utils import generate_block, gen_vote
pytestmark = [pytest.mark.execute] pytestmark = [pytest.mark.execute]
@ -341,22 +341,6 @@ def test_get_validator_update(b, node_keys, node_key, ed25519_node_keys):
# ============================================================================ # ============================================================================
# Helper functions # Helper functions
# ============================================================================ # ============================================================================
def to_inputs(election, i, ed25519_node_keys):
input0 = election.to_inputs()[i]
votes = election.outputs[i].amount
public_key0 = input0.owners_before[0]
key0 = ed25519_node_keys[public_key0]
return (input0, votes, key0)
def gen_vote(election, i, ed25519_node_keys):
(input_i, votes_i, key_i) = to_inputs(election, i, ed25519_node_keys)
election_pub_key = ValidatorElection.to_public_key(election.id)
return Vote.generate([input_i],
[([election_pub_key], votes_i)],
election_id=election.id)\
.sign([key_i.private_key])
def reset_validator_set(b, node_keys, height): def reset_validator_set(b, node_keys, height):
validators = [] validators = []

View File

@ -111,9 +111,9 @@ def test_upsert_validator_invalid_election(b_mock, new_validator, node_key, fixe
tx_election.validate(b_mock) tx_election.validate(b_mock)
def test_get_status_ongoing(b, ongoing_election, new_validator): def test_get_status_ongoing(b, ongoing_validator_election, new_validator):
status = ValidatorElection.ONGOING status = ValidatorElection.ONGOING
resp = ongoing_election.get_status(b) resp = ongoing_validator_election.get_status(b)
assert resp == status assert resp == status
@ -158,13 +158,13 @@ def test_get_status_inconclusive(b, inconclusive_election, new_validator):
assert resp == status assert resp == status
def test_upsert_validator_show(caplog, ongoing_election, b): def test_upsert_validator_show(caplog, ongoing_validator_election, b):
from bigchaindb.commands.bigchaindb import run_election_show from bigchaindb.commands.bigchaindb import run_election_show
election_id = ongoing_election.id election_id = ongoing_validator_election.id
public_key = public_key_to_base64(ongoing_election.asset['data']['public_key']['value']) public_key = public_key_to_base64(ongoing_validator_election.asset['data']['public_key']['value'])
power = ongoing_election.asset['data']['power'] power = ongoing_validator_election.asset['data']['power']
node_id = ongoing_election.asset['data']['node_id'] node_id = ongoing_validator_election.asset['data']['node_id']
status = ValidatorElection.ONGOING status = ValidatorElection.ONGOING
show_args = Namespace(action='show', show_args = Namespace(action='show',

View File

@ -4,8 +4,10 @@
from functools import singledispatch from functools import singledispatch
from bigchaindb import Vote
from bigchaindb.backend.localmongodb.connection import LocalMongoDBConnection from bigchaindb.backend.localmongodb.connection import LocalMongoDBConnection
from bigchaindb.backend.schema import TABLES from bigchaindb.backend.schema import TABLES
from bigchaindb.elections.election import Election
@singledispatch @singledispatch
@ -33,3 +35,20 @@ def generate_block(bigchain):
code, message = bigchain.write_transaction(tx, 'broadcast_tx_commit') code, message = bigchain.write_transaction(tx, 'broadcast_tx_commit')
assert code == 202 assert code == 202
time.sleep(2) time.sleep(2)
def to_inputs(election, i, ed25519_node_keys):
input0 = election.to_inputs()[i]
votes = election.outputs[i].amount
public_key0 = input0.owners_before[0]
key0 = ed25519_node_keys[public_key0]
return (input0, votes, key0)
def gen_vote(election, i, ed25519_node_keys):
(input_i, votes_i, key_i) = to_inputs(election, i, ed25519_node_keys)
election_pub_key = Election.to_public_key(election.id)
return Vote.generate([input_i],
[([election_pub_key], votes_i)],
election_id=election.id)\
.sign([key_i.private_key])