More test abstractions for multiple databases (#950)

* Remove unnecessary import of rethinkdb in a test

* Move test_run_query_util as a rethinkdb-specific test

* Move rethinkdb-specific command tests to own file

* Add __init__.py to new test folders

* Move command tests to their own test module

* Move fixtures out of command tests into separate conftest for commands

* Fix some small flake8 issues with rethinkdb's test_run_query_util

* Add pytest ignore hook to filter out test dirs that are not for the requested backend

* Move backend-specific tests in tests/db/ to tests/backend/
This commit is contained in:
Brett Sun 2016-12-16 22:17:13 +01:00 committed by GitHub
parent c81e7a7479
commit b4063dd9ad
10 changed files with 180 additions and 165 deletions

View File

View File

@ -25,7 +25,6 @@ def test_raise_exception_when_max_tries():
def test_reconnect_when_connection_lost():
import time
import rethinkdb as r
def raise_exception(*args, **kwargs):
raise r.ReqlDriverError('mock')
@ -65,18 +64,18 @@ def test_changefeed_reconnects_when_connection_lost(monkeypatch):
if self.tries == 1:
raise r.ReqlDriverError('mock')
elif self.tries == 2:
return { 'new_val': { 'fact': 'A group of cats is called a clowder.' },
'old_val': None }
return {'new_val': {'fact': 'A group of cats is called a clowder.'},
'old_val': None}
if self.tries == 3:
raise r.ReqlDriverError('mock')
elif self.tries == 4:
return { 'new_val': {'fact': 'Cats sleep 70% of their lives.' },
'old_val': None }
return {'new_val': {'fact': 'Cats sleep 70% of their lives.'},
'old_val': None}
else:
time.sleep(10)
changefeed = RethinkDBChangeFeed('cat_facts', ChangeFeed.INSERT,
connection=MockConnection())
connection=MockConnection())
changefeed.outqueue = mp.Queue()
t_changefeed = Thread(target=changefeed.run_forever, daemon=True)

View File

View File

@ -0,0 +1,41 @@
import pytest
@pytest.fixture
def mock_run_configure(monkeypatch):
from bigchaindb.commands import bigchain
monkeypatch.setattr(bigchain, 'run_configure', lambda *args, **kwargs: None)
@pytest.fixture
def mock_write_config(monkeypatch):
from bigchaindb import config_utils
monkeypatch.setattr(config_utils, 'write_config', lambda *args: None)
@pytest.fixture
def mock_db_init_with_existing_db(monkeypatch):
from bigchaindb.commands import bigchain
monkeypatch.setattr(bigchain, '_run_init', lambda: None)
@pytest.fixture
def mock_processes_start(monkeypatch):
from bigchaindb import processes
monkeypatch.setattr(processes, 'start', lambda *args: None)
@pytest.fixture
def mock_generate_key_pair(monkeypatch):
monkeypatch.setattr('bigchaindb.common.crypto.generate_key_pair', lambda: ('privkey', 'pubkey'))
@pytest.fixture
def mock_bigchaindb_backup_config(monkeypatch):
config = {
'keypair': {},
'database': {'host': 'host', 'port': 12345, 'name': 'adbname'},
'statsd': {'host': 'host', 'port': 12345, 'rate': 0.1},
'backlog_reassign_delay': 5
}
monkeypatch.setattr('bigchaindb._config', config)

View File

View File

@ -0,0 +1,123 @@
import pytest
import rethinkdb
from unittest.mock import Mock, patch
from argparse import Namespace
@patch('bigchaindb.commands.utils.start_rethinkdb', return_value=Mock())
def test_bigchain_run_start_with_rethinkdb(mock_start_rethinkdb,
mock_run_configure,
mock_processes_start,
mock_db_init_with_existing_db):
from bigchaindb.commands.bigchain import run_start
args = Namespace(start_rethinkdb=True, allow_temp_keypair=False, config=None, yes=True)
run_start(args)
mock_start_rethinkdb.assert_called_with()
@patch('subprocess.Popen')
def test_start_rethinkdb_returns_a_process_when_successful(mock_popen):
from bigchaindb.commands import utils
mock_popen.return_value = Mock(stdout=[
'Listening for client driver 1234',
'Server ready'])
assert utils.start_rethinkdb() is mock_popen.return_value
@patch('subprocess.Popen')
def test_start_rethinkdb_exits_when_cannot_start(mock_popen):
from bigchaindb.common import exceptions
from bigchaindb.commands import utils
mock_popen.return_value = Mock(stdout=['Nopety nope'])
with pytest.raises(exceptions.StartupError):
utils.start_rethinkdb()
@patch('rethinkdb.ast.Table.reconfigure')
def test_set_shards(mock_reconfigure, monkeypatch, b):
from bigchaindb.commands.bigchain import run_set_shards
# this will mock the call to retrieve the database config
# we will set it to return one replica
def mockreturn_one_replica(self, conn):
return {'shards': [{'replicas': [1]}]}
monkeypatch.setattr(rethinkdb.RqlQuery, 'run', mockreturn_one_replica)
args = Namespace(num_shards=3)
run_set_shards(args)
mock_reconfigure.assert_called_with(replicas=1, shards=3)
# this will mock the call to retrieve the database config
# we will set it to return three replica
def mockreturn_three_replicas(self, conn):
return {'shards': [{'replicas': [1, 2, 3]}]}
monkeypatch.setattr(rethinkdb.RqlQuery, 'run', mockreturn_three_replicas)
run_set_shards(args)
mock_reconfigure.assert_called_with(replicas=3, shards=3)
@patch('logging.Logger.warn')
def test_set_shards_raises_exception(mock_log, monkeypatch, b):
from bigchaindb.commands.bigchain import run_set_shards
# test that we are correctly catching the exception
def mock_raise(*args, **kwargs):
raise rethinkdb.ReqlOpFailedError('')
def mockreturn_one_replica(self, conn):
return {'shards': [{'replicas': [1]}]}
monkeypatch.setattr(rethinkdb.RqlQuery, 'run', mockreturn_one_replica)
monkeypatch.setattr(rethinkdb.ast.Table, 'reconfigure', mock_raise)
args = Namespace(num_shards=3)
run_set_shards(args)
assert mock_log.called
@patch('rethinkdb.ast.Table.reconfigure')
def test_set_replicas(mock_reconfigure, monkeypatch, b):
from bigchaindb.commands.bigchain import run_set_replicas
# this will mock the call to retrieve the database config
# we will set it to return two shards
def mockreturn_two_shards(self, conn):
return {'shards': [1, 2]}
monkeypatch.setattr(rethinkdb.RqlQuery, 'run', mockreturn_two_shards)
args = Namespace(num_replicas=2)
run_set_replicas(args)
mock_reconfigure.assert_called_with(replicas=2, shards=2)
# this will mock the call to retrieve the database config
# we will set it to return three shards
def mockreturn_three_shards(self, conn):
return {'shards': [1, 2, 3]}
monkeypatch.setattr(rethinkdb.RqlQuery, 'run', mockreturn_three_shards)
run_set_replicas(args)
mock_reconfigure.assert_called_with(replicas=2, shards=3)
@patch('logging.Logger.warn')
def test_set_replicas_raises_exception(mock_log, monkeypatch, b):
from bigchaindb.commands.bigchain import run_set_replicas
# test that we are correctly catching the exception
def mock_raise(*args, **kwargs):
raise rethinkdb.ReqlOpFailedError('')
def mockreturn_two_shards(self, conn):
return {'shards': [1, 2]}
monkeypatch.setattr(rethinkdb.RqlQuery, 'run', mockreturn_two_shards)
monkeypatch.setattr(rethinkdb.ast.Table, 'reconfigure', mock_raise)
args = Namespace(num_replicas=2)
run_set_replicas(args)
assert mock_log.called

View File

@ -4,47 +4,6 @@ from argparse import Namespace
import copy
import pytest
import rethinkdb
@pytest.fixture
def mock_run_configure(monkeypatch):
from bigchaindb.commands import bigchain
monkeypatch.setattr(bigchain, 'run_configure', lambda *args, **kwargs: None)
@pytest.fixture
def mock_write_config(monkeypatch):
from bigchaindb import config_utils
monkeypatch.setattr(config_utils, 'write_config', lambda *args: None)
@pytest.fixture
def mock_db_init_with_existing_db(monkeypatch):
from bigchaindb.commands import bigchain
monkeypatch.setattr(bigchain, '_run_init', lambda: None)
@pytest.fixture
def mock_processes_start(monkeypatch):
from bigchaindb import processes
monkeypatch.setattr(processes, 'start', lambda *args: None)
@pytest.fixture
def mock_generate_key_pair(monkeypatch):
monkeypatch.setattr('bigchaindb.common.crypto.generate_key_pair', lambda: ('privkey', 'pubkey'))
@pytest.fixture
def mock_bigchaindb_backup_config(monkeypatch):
config = {
'keypair': {},
'database': {'host': 'host', 'port': 12345, 'name': 'adbname'},
'statsd': {'host': 'host', 'port': 12345, 'rate': 0.1},
'backlog_reassign_delay': 5
}
monkeypatch.setattr('bigchaindb._config', config)
def test_make_sure_we_dont_remove_any_command():
@ -114,18 +73,6 @@ def test_bigchain_run_start(mock_run_configure, mock_processes_start, mock_db_in
run_start(args)
@patch('bigchaindb.commands.utils.start_rethinkdb', return_value=Mock())
def test_bigchain_run_start_with_rethinkdb(mock_start_rethinkdb,
mock_run_configure,
mock_processes_start,
mock_db_init_with_existing_db):
from bigchaindb.commands.bigchain import run_start
args = Namespace(start_rethinkdb=True, allow_temp_keypair=False, config=None, yes=True)
run_start(args)
mock_start_rethinkdb.assert_called_with()
@pytest.mark.skipif(reason="BigchainDB doesn't support the automatic creation of a config file anymore")
def test_bigchain_run_start_assume_yes_create_default_config(monkeypatch, mock_processes_start,
mock_generate_key_pair, mock_db_init_with_existing_db):
@ -280,24 +227,6 @@ def test_run_configure_when_config_does_exist(monkeypatch,
assert value == {}
@patch('subprocess.Popen')
def test_start_rethinkdb_returns_a_process_when_successful(mock_popen):
from bigchaindb.commands import utils
mock_popen.return_value = Mock(stdout=[
'Listening for client driver 1234',
'Server ready'])
assert utils.start_rethinkdb() is mock_popen.return_value
@patch('subprocess.Popen')
def test_start_rethinkdb_exits_when_cannot_start(mock_popen):
from bigchaindb.common import exceptions
from bigchaindb.commands import utils
mock_popen.return_value = Mock(stdout=['Nopety nope'])
with pytest.raises(exceptions.StartupError):
utils.start_rethinkdb()
@patch('bigchaindb.common.crypto.generate_key_pair',
return_value=('private_key', 'public_key'))
@pytest.mark.usefixtures('restore_config')
@ -339,94 +268,6 @@ def test_allow_temp_keypair_doesnt_override_if_keypair_found(mock_gen_keypair,
assert bigchaindb.config['keypair']['public'] == original_public_key
@patch('rethinkdb.ast.Table.reconfigure')
def test_set_shards(mock_reconfigure, monkeypatch, b):
from bigchaindb.commands.bigchain import run_set_shards
# this will mock the call to retrieve the database config
# we will set it to return one replica
def mockreturn_one_replica(self, conn):
return {'shards': [{'replicas': [1]}]}
monkeypatch.setattr(rethinkdb.RqlQuery, 'run', mockreturn_one_replica)
args = Namespace(num_shards=3)
run_set_shards(args)
mock_reconfigure.assert_called_with(replicas=1, shards=3)
# this will mock the call to retrieve the database config
# we will set it to return three replica
def mockreturn_three_replicas(self, conn):
return {'shards': [{'replicas': [1, 2, 3]}]}
monkeypatch.setattr(rethinkdb.RqlQuery, 'run', mockreturn_three_replicas)
run_set_shards(args)
mock_reconfigure.assert_called_with(replicas=3, shards=3)
@patch('logging.Logger.warn')
def test_set_shards_raises_exception(mock_log, monkeypatch, b):
from bigchaindb.commands.bigchain import run_set_shards
# test that we are correctly catching the exception
def mock_raise(*args, **kwargs):
raise rethinkdb.ReqlOpFailedError('')
def mockreturn_one_replica(self, conn):
return {'shards': [{'replicas': [1]}]}
monkeypatch.setattr(rethinkdb.RqlQuery, 'run', mockreturn_one_replica)
monkeypatch.setattr(rethinkdb.ast.Table, 'reconfigure', mock_raise)
args = Namespace(num_shards=3)
run_set_shards(args)
assert mock_log.called
@patch('rethinkdb.ast.Table.reconfigure')
def test_set_replicas(mock_reconfigure, monkeypatch, b):
from bigchaindb.commands.bigchain import run_set_replicas
# this will mock the call to retrieve the database config
# we will set it to return two shards
def mockreturn_two_shards(self, conn):
return {'shards': [1, 2]}
monkeypatch.setattr(rethinkdb.RqlQuery, 'run', mockreturn_two_shards)
args = Namespace(num_replicas=2)
run_set_replicas(args)
mock_reconfigure.assert_called_with(replicas=2, shards=2)
# this will mock the call to retrieve the database config
# we will set it to return three shards
def mockreturn_three_shards(self, conn):
return {'shards': [1, 2, 3]}
monkeypatch.setattr(rethinkdb.RqlQuery, 'run', mockreturn_three_shards)
run_set_replicas(args)
mock_reconfigure.assert_called_with(replicas=2, shards=3)
@patch('logging.Logger.warn')
def test_set_replicas_raises_exception(mock_log, monkeypatch, b):
from bigchaindb.commands.bigchain import run_set_replicas
# test that we are correctly catching the exception
def mock_raise(*args, **kwargs):
raise rethinkdb.ReqlOpFailedError('')
def mockreturn_two_shards(self, conn):
return {'shards': [1, 2]}
monkeypatch.setattr(rethinkdb.RqlQuery, 'run', mockreturn_two_shards)
monkeypatch.setattr(rethinkdb.ast.Table, 'reconfigure', mock_raise)
args = Namespace(num_replicas=2)
run_set_replicas(args)
assert mock_log.called
@patch('argparse.ArgumentParser.parse_args')
@patch('bigchaindb.commands.utils.base_parser')
@patch('bigchaindb.commands.utils.start')

View File

@ -44,6 +44,17 @@ def pytest_addoption(parser):
)
def pytest_ignore_collect(path, config):
from bigchaindb.backend.connection import BACKENDS
path = str(path)
if os.path.isdir(path):
dirname = os.path.split(path)[1]
if dirname in BACKENDS.keys() and dirname != config.getoption('--database-backend'):
print('Ignoring unrequested backend test dir: ', path)
return True
# We need this function to avoid loading an existing
# conf file located in the home of the user running
# the tests. If it's too aggressive we can change it