diff --git a/bigchaindb/core.py b/bigchaindb/core.py index 286336a0..76d90a58 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -7,7 +7,7 @@ import rapidjson from datetime import datetime import bigchaindb -import bigchaindb.config_utils +from bigchaindb import config_utils from bigchaindb import exceptions from bigchaindb.crypto import hash_data, PublicKey, PrivateKey, generate_key_pair @@ -15,6 +15,7 @@ from bigchaindb.crypto import hash_data, PublicKey, PrivateKey, generate_key_pai class GenesisBlockAlreadyExistsError(Exception): pass + class KeypairNotFoundException(Exception): pass @@ -45,7 +46,7 @@ class Bigchain(object): keyring (list[str]): list of base58 encoded public keys of the federation nodes. """ - bigchaindb.config_utils.autoconfigure() + config_utils.autoconfigure() self.host = host or bigchaindb.config['database']['host'] self.port = port or bigchaindb.config['database']['port'] self.dbname = dbname or bigchaindb.config['database']['name'] diff --git a/tests/conftest.py b/tests/conftest.py index 4a6ca97e..a6006ac2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,9 +8,6 @@ Tasks: import pytest -import bigchaindb -import bigchaindb.config_utils - config = { 'database': { @@ -27,23 +24,22 @@ USER_PRIVATE_KEY = 'GmRZxQdQv7tooMijXytQkexKuFN6mJocciJarAmMwTX2' USER_PUBLIC_KEY = 'r3cEu8GNoz8rYpNJ61k7GqfR8VEvdUbtyHce8u1kaYwh' -@pytest.fixture(scope='function', autouse=True) -def restore_config(request): - bigchaindb.config_utils.dict_config(config) +@pytest.fixture +def restore_config(request, node_config): + from bigchaindb import config_utils + config_utils.dict_config(node_config) -# FIXME: make this fixtures work :) -# @pytest.fixture -# def config(): -# return config -# -# -# @pytest.fixture -# def user_private_key(): -# return USER_PRIVATE_KEY -# -# -# @pytest.fixture -# def user_public_key(): -# return USER_PUBLIC_KEY -# +@pytest.fixture +def node_config(): + return config + + +@pytest.fixture +def user_private_key(): + return USER_PRIVATE_KEY + + +@pytest.fixture +def user_public_key(): + return USER_PUBLIC_KEY diff --git a/tests/db/conftest.py b/tests/db/conftest.py index 438f30e5..a9a85d71 100644 --- a/tests/db/conftest.py +++ b/tests/db/conftest.py @@ -12,11 +12,16 @@ import rethinkdb as r from bigchaindb import Bigchain from bigchaindb.db import get_conn -from ..conftest import config, USER_PRIVATE_KEY, USER_PUBLIC_KEY - NOOP = None + +@pytest.fixture(autouse=True) +def restore_config(request, node_config): + from bigchaindb import config_utils + config_utils.dict_config(node_config) + + @pytest.fixture(scope='module', autouse=True) def setup_database(request): print('Initializing test db') diff --git a/tests/db/test_bigchain_api.py b/tests/db/test_bigchain_api.py index 1c40c314..ca082ba9 100644 --- a/tests/db/test_bigchain_api.py +++ b/tests/db/test_bigchain_api.py @@ -12,11 +12,8 @@ from bigchaindb.crypto import hash_data, PrivateKey, PublicKey, generate_key_pai from bigchaindb.voter import Voter from bigchaindb.block import Block -import bigchaindb.config_utils -from .conftest import USER_PUBLIC_KEY, USER_PRIVATE_KEY - -def create_inputs(amount=1, b=None): +def create_inputs(user_public_key, amount=1, b=None): # 1. create the genesis block b = b or Bigchain() try: @@ -27,7 +24,7 @@ def create_inputs(amount=1, b=None): # 2. create block with transactions for `USER` to spend transactions = [] for i in range(amount): - tx = b.create_transaction(b.me, USER_PUBLIC_KEY, None, 'CREATE') + tx = b.create_transaction(b.me, user_public_key, None, 'CREATE') tx_signed = b.sign_transaction(tx, b.me_private) transactions.append(tx_signed) b.write_transaction(tx_signed) @@ -37,6 +34,11 @@ def create_inputs(amount=1, b=None): return block +@pytest.fixture +def inputs(user_public_key): + return create_inputs(user_public_key) + + @pytest.mark.skipif(reason='Some tests throw a ResourceWarning that might result in some weird ' 'exceptions while running the tests. The problem seems to *not* ' 'interfere with the correctness of the tests. ') @@ -86,11 +88,11 @@ class TestBigchainApi(object): tx = b.create_transaction('a', 'b', 'c', 'd') assert b.deserialize(b.serialize(tx)) == tx - def test_write_transaction(self, b): - create_inputs() - input_tx = b.get_owned_ids(USER_PUBLIC_KEY).pop() - tx = b.create_transaction(USER_PUBLIC_KEY, 'b', input_tx, 'd') - tx_signed = b.sign_transaction(tx, USER_PRIVATE_KEY) + @pytest.mark.usefixtures('inputs') + def test_write_transaction(self, b, user_public_key, user_private_key): + input_tx = b.get_owned_ids(user_public_key).pop() + tx = b.create_transaction(user_public_key, 'b', input_tx, 'd') + tx_signed = b.sign_transaction(tx, user_private_key) response = b.write_transaction(tx_signed) assert response['skipped'] == 0 @@ -100,11 +102,11 @@ class TestBigchainApi(object): assert response['replaced'] == 0 assert response['inserted'] == 1 - def test_read_transaction(self, b): - create_inputs() - input_tx = b.get_owned_ids(USER_PUBLIC_KEY).pop() - tx = b.create_transaction(USER_PUBLIC_KEY, 'b', input_tx, 'd') - tx_signed = b.sign_transaction(tx, USER_PRIVATE_KEY) + @pytest.mark.usefixtures('inputs') + def test_read_transaction(self, b, user_public_key, user_private_key): + input_tx = b.get_owned_ids(user_public_key).pop() + tx = b.create_transaction(user_public_key, 'b', input_tx, 'd') + tx_signed = b.sign_transaction(tx, user_private_key) b.write_transaction(tx_signed) # create block and write it to the bighcain before retrieving the transaction @@ -114,11 +116,11 @@ class TestBigchainApi(object): response = b.get_transaction(tx_signed["id"]) assert b.serialize(tx_signed) == b.serialize(response) - def test_assign_transaction_one_node(self, b): - create_inputs() - input_tx = b.get_owned_ids(USER_PUBLIC_KEY).pop() - tx = b.create_transaction(USER_PUBLIC_KEY, 'b', input_tx, 'd') - tx_signed = b.sign_transaction(tx, USER_PRIVATE_KEY) + @pytest.mark.usefixtures('inputs') + def test_assign_transaction_one_node(self, b, user_public_key, user_private_key): + input_tx = b.get_owned_ids(user_public_key).pop() + tx = b.create_transaction(user_public_key, 'b', input_tx, 'd') + tx_signed = b.sign_transaction(tx, user_private_key) b.write_transaction(tx_signed) # retrieve the transaction @@ -127,17 +129,17 @@ class TestBigchainApi(object): # check if the assignee is the current node assert response['assignee'] == b.me - def test_assign_transaction_multiple_nodes(self, b): + def test_assign_transaction_multiple_nodes(self, b, user_public_key, user_private_key): # create 5 federation nodes for _ in range(5): b.federation_nodes.append(b.generate_keys()[1]) - create_inputs(20, b=b) + create_inputs(user_public_key, amount=20, b=b) # test assignee for several transactions for _ in range(20): - input_tx = b.get_owned_ids(USER_PUBLIC_KEY).pop() - tx = b.create_transaction(USER_PUBLIC_KEY, 'b', input_tx, 'd') - tx_signed = b.sign_transaction(tx, USER_PRIVATE_KEY) + input_tx = b.get_owned_ids(user_public_key).pop() + tx = b.create_transaction(user_public_key, 'b', input_tx, 'd') + tx_signed = b.sign_transaction(tx, user_private_key) b.write_transaction(tx_signed) # retrieve the transaction @@ -146,8 +148,8 @@ class TestBigchainApi(object): # check if the assignee is the federation_nodes assert response['assignee'] in b.federation_nodes + @pytest.mark.usefixtures('inputs') def test_genesis_block(self, b): - create_inputs() response = list(r.table('bigchain') .filter(r.row['block_number'] == 0) .run(b.conn))[0] @@ -280,9 +282,9 @@ class TestTransactionValidation(object): assert excinfo.value.args[0] == 'input `c` does not exist in the bigchain' assert b.is_valid_transaction(tx) == False - def test_non_create_valid_input_wrong_owner(self, b): - create_inputs() - valid_input = b.get_owned_ids(USER_PUBLIC_KEY).pop() + @pytest.mark.usefixtures('inputs') + def test_non_create_valid_input_wrong_owner(self, b, user_public_key): + valid_input = b.get_owned_ids(user_public_key).pop() tx = b.create_transaction('a', 'b', valid_input, 'c') with pytest.raises(exceptions.TransactionOwnerError) as excinfo: b.validate_transaction(tx) @@ -290,11 +292,11 @@ class TestTransactionValidation(object): assert excinfo.value.args[0] == 'current_owner `a` does not own the input `{}`'.format(valid_input) assert b.is_valid_transaction(tx) == False - def test_non_create_double_spend(self, b): - create_inputs() - input_valid = b.get_owned_ids(USER_PUBLIC_KEY).pop() - tx_valid = b.create_transaction(USER_PUBLIC_KEY, 'b', input_valid, 'd') - tx_valid_signed = b.sign_transaction(tx_valid, USER_PRIVATE_KEY) + @pytest.mark.usefixtures('inputs') + def test_non_create_double_spend(self, b, user_public_key, user_private_key): + input_valid = b.get_owned_ids(user_public_key).pop() + tx_valid = b.create_transaction(user_public_key, 'b', input_valid, 'd') + tx_valid_signed = b.sign_transaction(tx_valid, user_private_key) b.write_transaction(tx_valid_signed) # create and write block to bigchain @@ -302,17 +304,17 @@ class TestTransactionValidation(object): b.write_block(block, durability='hard') # create another transaction with the same input - tx_double_spend = b.create_transaction(USER_PUBLIC_KEY, 'd', input_valid, 'd') + tx_double_spend = b.create_transaction(user_public_key, 'd', input_valid, 'd') with pytest.raises(exceptions.DoubleSpend) as excinfo: b.validate_transaction(tx_double_spend) assert excinfo.value.args[0] == 'input `{}` was already spent'.format(input_valid) assert b.is_valid_transaction(tx_double_spend) == False - def test_wrong_transaction_hash(self, b): - create_inputs() - input_valid = b.get_owned_ids(USER_PUBLIC_KEY).pop() - tx_valid = b.create_transaction(USER_PUBLIC_KEY, 'b', input_valid, 'd') + @pytest.mark.usefixtures('inputs') + def test_wrong_transaction_hash(self, b, user_public_key): + input_valid = b.get_owned_ids(user_public_key).pop() + tx_valid = b.create_transaction(user_public_key, 'b', input_valid, 'd') # change the transaction hash tx_valid.update({'id': 'abcd'}) @@ -320,10 +322,10 @@ class TestTransactionValidation(object): b.validate_transaction(tx_valid) assert b.is_valid_transaction(tx_valid) == False - def test_wrong_signature(self, b): - create_inputs() - input_valid = b.get_owned_ids(USER_PUBLIC_KEY).pop() - tx_valid = b.create_transaction(USER_PUBLIC_KEY, 'b', input_valid, 'd') + @pytest.mark.usefixtures('inputs') + def test_wrong_signature(self, b, user_public_key): + input_valid = b.get_owned_ids(user_public_key).pop() + tx_valid = b.create_transaction(user_public_key, 'b', input_valid, 'd') wrong_private_key = '4fyvJe1aw2qHZ4UNRYftXK7JU7zy9bCqoU5ps6Ne3xrY' @@ -332,18 +334,18 @@ class TestTransactionValidation(object): b.validate_transaction(tx_invalid_signed) assert b.is_valid_transaction(tx_invalid_signed) == False - def test_valid_create_transaction(self, b): - tx = b.create_transaction(b.me, USER_PUBLIC_KEY, None, 'CREATE') + def test_valid_create_transaction(self, b, user_public_key): + tx = b.create_transaction(b.me, user_public_key, None, 'CREATE') tx_signed = b.sign_transaction(tx, b.me_private) assert tx_signed == b.validate_transaction(tx_signed) assert tx_signed == b.is_valid_transaction(tx_signed) - def test_valid_non_create_transaction(self, b): - create_inputs() - input_valid = b.get_owned_ids(USER_PUBLIC_KEY).pop() - tx_valid = b.create_transaction(USER_PUBLIC_KEY, 'b', input_valid, 'd') + @pytest.mark.usefixtures('inputs') + def test_valid_non_create_transaction(self, b, user_public_key, user_private_key): + input_valid = b.get_owned_ids(user_public_key).pop() + tx_valid = b.create_transaction(user_public_key, 'b', input_valid, 'd') - tx_valid_signed = b.sign_transaction(tx_valid, USER_PRIVATE_KEY) + tx_valid_signed = b.sign_transaction(tx_valid, user_private_key) assert tx_valid_signed == b.validate_transaction(tx_valid_signed) assert tx_valid_signed == b.is_valid_transaction(tx_valid_signed) @@ -359,10 +361,10 @@ class TestBlockValidation(object): b.validate_block(block) @pytest.mark.skipif(reason='Separated tx validation from block creation.') - def test_invalid_transactions_in_block(self, b): + @pytest.mark.usefixtures('inputs') + def test_invalid_transactions_in_block(self, b, user_public_key, ): # invalid transaction - create_inputs() - valid_input = b.get_owned_ids(USER_PUBLIC_KEY).pop() + valid_input = b.get_owned_ids(user_public_key).pop() tx_invalid = b.create_transaction('a', 'b', valid_input, 'c') block = b.create_block([tx_invalid]) @@ -400,12 +402,12 @@ class TestBlockValidation(object): with pytest.raises(exceptions.InvalidHash): b.validate_block(block) - def test_valid_block(self, b): - create_inputs() + @pytest.mark.usefixtures('inputs') + def test_valid_block(self, b, user_public_key, user_private_key): # create valid transaction - input_valid = b.get_owned_ids(USER_PUBLIC_KEY).pop() - tx_valid = b.create_transaction(USER_PUBLIC_KEY, 'b', input_valid, 'd') - tx_valid_signed = b.sign_transaction(tx_valid, USER_PRIVATE_KEY) + input_valid = b.get_owned_ids(user_public_key).pop() + tx_valid = b.create_transaction(user_public_key, 'b', input_valid, 'd') + tx_valid_signed = b.sign_transaction(tx_valid, user_private_key) # create valid block block = b.create_block([tx_valid_signed]) @@ -491,13 +493,13 @@ class TestBigchainVoter(object): assert vote['node_pubkey'] == b.me assert PublicKey(b.me).verify(b.serialize(vote['vote']), vote['signature']) == True - def test_invalid_block_voting(self, b): + def test_invalid_block_voting(self, b, user_public_key): # create queue and voter q_new_block = mp.Queue() voter = Voter(q_new_block) # create transaction - transaction = b.create_transaction(b.me, USER_PUBLIC_KEY, None, 'CREATE') + transaction = b.create_transaction(b.me, user_public_key, None, 'CREATE') transaction_signed = b.sign_transaction(transaction, b.me_private) genesis = b.create_genesis_block() @@ -564,12 +566,12 @@ class TestBigchainVoter(object): class TestBigchainBlock(object): - def test_by_assignee(self, b): + def test_by_assignee(self, b, user_public_key): # create transactions and randomly assigne them transactions = mp.Queue() count_assigned_to_me = 0 for i in range(100): - tx = b.create_transaction(b.me, USER_PUBLIC_KEY, None, 'CREATE') + tx = b.create_transaction(b.me, user_public_key, None, 'CREATE') assignee = random.choice([b.me, 'aaa', 'bbb', 'ccc']) if assignee == b.me: count_assigned_to_me += 1 @@ -588,13 +590,13 @@ class TestBigchainBlock(object): # the queue minus 'stop' assert block.q_tx_to_validate.qsize() - 1 == count_assigned_to_me - def test_validate_transactions(self, b): + def test_validate_transactions(self, b, user_public_key): # create transactions and randomly invalidate some of them by changing the hash transactions = mp.Queue() count_valid = 0 for i in range(100): valid = random.choice([True, False]) - tx = b.create_transaction(b.me, USER_PUBLIC_KEY, None, 'CREATE') + tx = b.create_transaction(b.me, user_public_key, None, 'CREATE') tx = b.sign_transaction(tx, b.me_private) if not valid: tx['id'] = 'a' * 64 @@ -613,11 +615,11 @@ class TestBigchainBlock(object): assert block.q_tx_validated.qsize() - 1 == count_valid assert block.q_tx_delete.qsize() - 1 == 100 - def test_create_block(self, b): + def test_create_block(self, b, user_public_key): # create transactions transactions = mp.Queue() for i in range(100): - tx = b.create_transaction(b.me, USER_PUBLIC_KEY, None, 'CREATE') + tx = b.create_transaction(b.me, user_public_key, None, 'CREATE') tx = b.sign_transaction(tx, b.me_private) transactions.put(tx) transactions.put('stop') @@ -631,12 +633,12 @@ class TestBigchainBlock(object): # check if the number of valid transactions assert block.q_block.qsize() - 1 == 1 - def test_write_block(self, b): + def test_write_block(self, b, user_public_key): # create transactions transactions = [] blocks = mp.Queue() for i in range(100): - tx = b.create_transaction(b.me, USER_PUBLIC_KEY, None, 'CREATE') + tx = b.create_transaction(b.me, user_public_key, None, 'CREATE') tx = b.sign_transaction(tx, b.me_private) transactions.append(tx) @@ -661,14 +663,14 @@ class TestBigchainBlock(object): # check if the number of blocks in bigchain increased assert r.table('bigchain').count() == 2 - def test_delete_transactions(self, b): + def test_delete_transactions(self, b, user_public_key): # make sure that there are no transactions in the backlog r.table('backlog').delete().run(b.conn) # create and write transactions to the backlog transactions = mp.Queue() for i in range(100): - tx = b.create_transaction(b.me, USER_PUBLIC_KEY, None, 'CREATE') + tx = b.create_transaction(b.me, user_public_key, None, 'CREATE') tx = b.sign_transaction(tx, b.me_private) b.write_transaction(tx) transactions.put(tx['id']) @@ -689,13 +691,13 @@ class TestBigchainBlock(object): # check if all transactions were deleted from the backlog assert r.table('backlog').count() == 0 - def test_bootstrap(self, b): + def test_bootstrap(self, b, user_public_key): # make sure that there are no transactions in the backlog r.table('backlog').delete().run(b.conn) # create and write transactions to the backlog for i in range(100): - tx = b.create_transaction(b.me, USER_PUBLIC_KEY, None, 'CREATE') + tx = b.create_transaction(b.me, user_public_key, None, 'CREATE') tx = b.sign_transaction(tx, b.me_private) b.write_transaction(tx) @@ -708,7 +710,7 @@ class TestBigchainBlock(object): # we should have gotten a queue with 100 results assert initial_results.qsize() - 1 == 100 - def test_start(self, b): + def test_start(self, b, user_public_key): # start with 100 transactions in the backlog and 100 in the changefeed # make sure that there are no transactions in the backlog @@ -716,14 +718,14 @@ class TestBigchainBlock(object): # create and write transactions to the backlog for i in range(100): - tx = b.create_transaction(b.me, USER_PUBLIC_KEY, None, 'CREATE') + tx = b.create_transaction(b.me, user_public_key, None, 'CREATE') tx = b.sign_transaction(tx, b.me_private) b.write_transaction(tx) # create 100 more transactions to emulate the changefeed new_transactions = mp.Queue() for i in range(100): - tx = b.create_transaction(b.me, USER_PUBLIC_KEY, None, 'CREATE') + tx = b.create_transaction(b.me, user_public_key, None, 'CREATE') tx = b.sign_transaction(tx, b.me_private) b.write_transaction(tx) new_transactions.put(tx) diff --git a/tests/db/test_voter.py b/tests/db/test_voter.py index c5af20e9..26c2bac0 100644 --- a/tests/db/test_voter.py +++ b/tests/db/test_voter.py @@ -7,8 +7,6 @@ from bigchaindb import Bigchain from bigchaindb.voter import Voter, BlockStream from bigchaindb.crypto import PublicKey -from .conftest import USER_PUBLIC_KEY - class TestBigchainVoter(object): @@ -50,13 +48,13 @@ class TestBigchainVoter(object): assert PublicKey(b.me).verify(b.serialize(vote['vote']), vote['signature']) == True - def test_invalid_block_voting(self, b): + def test_invalid_block_voting(self, b, user_public_key): # create queue and voter q_new_block = mp.Queue() voter = Voter(q_new_block) # create transaction - transaction = b.create_transaction(b.me, USER_PUBLIC_KEY, None, 'CREATE') + transaction = b.create_transaction(b.me, user_public_key, None, 'CREATE') transaction_signed = b.sign_transaction(transaction, b.me_private) genesis = b.create_genesis_block() diff --git a/tests/test_core.py b/tests/test_core.py new file mode 100644 index 00000000..6374b8be --- /dev/null +++ b/tests/test_core.py @@ -0,0 +1,59 @@ +import copy +import pytest + + +@pytest.fixture +def config(request): + import bigchaindb + config = { + 'database': { + 'host': 'host', + 'port': 28015, + 'name': 'bigchain', + }, + 'keypair': { + 'public': 'pubkey', + 'private': 'privkey', + }, + 'keyring': [], + 'CONFIGURED': True, + } + bigchaindb.config.update(config) + + def fin(): + bigchaindb.config = bigchaindb._config + bigchaindb._config = copy.deepcopy(bigchaindb._config) + request.addfinalizer(fin) + return bigchaindb.config + + +def test_bigchain_class_default_initialization(config): + from bigchaindb.core import Bigchain + bigchain = Bigchain() + assert bigchain.host == config['database']['host'] + assert bigchain.port == config['database']['port'] + assert bigchain.dbname == config['database']['name'] + assert bigchain.me == config['keypair']['public'] + assert bigchain.me_private == config['keypair']['private'] + assert bigchain.federation_nodes == config['keyring'] + assert bigchain._conn is None + + +def test_bigchain_class_initialization_with_parameters(config): + from bigchaindb.core import Bigchain + init_kwargs = { + 'host': 'some_node', + 'port': '12345', + 'dbname': 'atom', + 'public_key': 'white', + 'private_key': 'black', + 'keyring': ['key_one', 'key_two'], + } + bigchain = Bigchain(**init_kwargs) + assert bigchain.host == init_kwargs['host'] + assert bigchain.port == init_kwargs['port'] + assert bigchain.dbname == init_kwargs['dbname'] + assert bigchain.me == init_kwargs['public_key'] + assert bigchain.me_private == init_kwargs['private_key'] + assert bigchain.federation_nodes == init_kwargs['keyring'] + assert bigchain._conn is None diff --git a/tests/utils/test_config_utils.py b/tests/utils/test_config_utils.py index adbdbe37..54c425b4 100644 --- a/tests/utils/test_config_utils.py +++ b/tests/utils/test_config_utils.py @@ -3,7 +3,6 @@ import copy import pytest import bigchaindb -from bigchaindb import config_utils ORIGINAL_CONFIG = copy.deepcopy(bigchaindb.config) @@ -15,6 +14,7 @@ def clean_config(): def test_bigchain_instance_is_initialized_when_conf_provided(): + from bigchaindb import config_utils assert 'CONFIGURED' not in bigchaindb.config config_utils.dict_config({'keypair': {'public': 'a', 'private': 'b'}}) @@ -27,6 +27,7 @@ def test_bigchain_instance_is_initialized_when_conf_provided(): def test_bigchain_instance_raises_when_not_configured(monkeypatch): + from bigchaindb import config_utils assert 'CONFIGURED' not in bigchaindb.config # We need to disable ``bigchaindb.config_utils.autoconfigure`` to avoid reading @@ -35,4 +36,3 @@ def test_bigchain_instance_raises_when_not_configured(monkeypatch): with pytest.raises(bigchaindb.core.KeypairNotFoundException): bigchaindb.Bigchain() -