From 391da2cf604287acf217051acd2743f65a8b94a8 Mon Sep 17 00:00:00 2001 From: Rodolphe Marques Date: Wed, 25 Jan 2017 12:36:08 +0100 Subject: [PATCH] Added tests --- bigchaindb/backend/admin.py | 6 +- bigchaindb/commands/bigchain.py | 4 +- tests/backend/mongodb/test_admin.py | 118 ++++++++++++++++++++++++++++ tests/backend/test_generics.py | 2 + tests/commands/test_commands.py | 54 ++++++++++++- 5 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 tests/backend/mongodb/test_admin.py diff --git a/bigchaindb/backend/admin.py b/bigchaindb/backend/admin.py index da54397b..f0ea62fd 100644 --- a/bigchaindb/backend/admin.py +++ b/bigchaindb/backend/admin.py @@ -24,9 +24,11 @@ def set_replicas(connection, *, replicas): @singledispatch def add_replicas(connection, replicas): - raise NotImplementedError + raise NotImplementedError('This command is specific to the ' + 'MongoDB backend.') @singledispatch def remove_replicas(connection, replicas): - raise NotImplementedError + raise NotImplementedError('This command is specific to the ' + 'MongoDB backend.') diff --git a/bigchaindb/commands/bigchain.py b/bigchaindb/commands/bigchain.py index 78b3b745..98e9d81c 100644 --- a/bigchaindb/commands/bigchain.py +++ b/bigchaindb/commands/bigchain.py @@ -277,7 +277,7 @@ def run_add_replicas(args): try: add_replicas(conn, args.replicas) - except DatabaseOpFailedError as e: + except (DatabaseOpFailedError, NotImplementedError) as e: logger.warn(e) else: logger.info('Added {} to the replicaset.'.format(args.replicas)) @@ -290,7 +290,7 @@ def run_remove_replicas(args): try: remove_replicas(conn, args.replicas) - except DatabaseOpFailedError as e: + except (DatabaseOpFailedError, NotImplementedError) as e: logger.warn(e) else: logger.info('Removed {} from the replicaset.'.format(args.replicas)) diff --git a/tests/backend/mongodb/test_admin.py b/tests/backend/mongodb/test_admin.py new file mode 100644 index 00000000..138bc616 --- /dev/null +++ b/tests/backend/mongodb/test_admin.py @@ -0,0 +1,118 @@ +"""Tests for the :mod:`bigchaindb.backend.mongodb.admin` module.""" +import copy +from unittest import mock + +import pytest +from pymongo.database import Database +from pymongo.errors import OperationFailure + + +@pytest.fixture +def mock_replicaset_config(): + return { + 'config': { + '_id': 'bigchain-rs', + 'members': [ + { + '_id': 0, + 'arbiterOnly': False, + 'buildIndexes': True, + 'hidden': False, + 'host': 'localhost:27017', + 'priority': 1.0, + 'slaveDelay': 0, + 'tags': {}, + 'votes': 1 + } + ], + 'version': 1 + } + } + + +def test_add_replicas(mock_replicaset_config): + from bigchaindb.backend import connect + from bigchaindb.backend.admin import add_replicas + + connection = connect() + # force the connection object to setup a connection to the database + # before we mock `Database.command` + connection.conn + + expected_config = copy.deepcopy(mock_replicaset_config) + expected_config['config']['members'] += [ + {'_id': 1, 'host': 'localhost:27018'}, + {'_id': 2, 'host': 'localhost:27019'} + ] + expected_config['config']['version'] += 1 + + with mock.patch.object(Database, 'command') as mock_command: + mock_command.return_value = mock_replicaset_config + add_replicas(connection, ['localhost:27018', 'localhost:27019']) + + mock_command.assert_called_with('replSetReconfig', + expected_config['config']) + + +def test_add_replicas_raises(mock_replicaset_config): + from bigchaindb.backend import connect + from bigchaindb.backend.admin import add_replicas + from bigchaindb.backend.exceptions import DatabaseOpFailedError + + connection = connect() + # force the connection object to setup a connection to the database + # before we mock `Database.command` + connection.conn + + with mock.patch.object(Database, 'command') as mock_command: + mock_command.side_effect = [ + mock_replicaset_config, + OperationFailure(error=1, details={'errmsg': ''}) + ] + with pytest.raises(DatabaseOpFailedError): + add_replicas(connection, ['localhost:27018']) + + +def test_remove_replicas(mock_replicaset_config): + from bigchaindb.backend import connect + from bigchaindb.backend.admin import remove_replicas + + connection = connect() + # force the connection object to setup a connection to the database + # before we mock `Database.command` + connection.conn + + expected_config = copy.deepcopy(mock_replicaset_config) + expected_config['config']['version'] += 1 + + # add some hosts to the configuration to remove + mock_replicaset_config['config']['members'] += [ + {'_id': 1, 'host': 'localhost:27018'}, + {'_id': 2, 'host': 'localhost:27019'} + ] + + with mock.patch.object(Database, 'command') as mock_command: + mock_command.return_value = mock_replicaset_config + remove_replicas(connection, ['localhost:27018', 'localhost:27019']) + + mock_command.assert_called_with('replSetReconfig', + expected_config['config']) + + +def test_remove_replicas_raises(mock_replicaset_config): + from bigchaindb.backend import connect + from bigchaindb.backend.admin import remove_replicas + from bigchaindb.backend.exceptions import DatabaseOpFailedError + + connection = connect() + # force the connection object to setup a connection to the database + # before we mock `Database.command` + connection.conn + + with mock.patch.object(Database, 'command') as mock_command: + mock_command.side_effect = [ + mock_replicaset_config, + OperationFailure(error=1, details={'errmsg': ''}) + ] + with pytest.raises(DatabaseOpFailedError): + remove_replicas(connection, ['localhost:27018']) diff --git a/tests/backend/test_generics.py b/tests/backend/test_generics.py index 2049d72b..0dd2637f 100644 --- a/tests/backend/test_generics.py +++ b/tests/backend/test_generics.py @@ -100,6 +100,8 @@ def test_init_database(mock_create_database, mock_create_tables, ('reconfigure', {'table': None, 'shards': None, 'replicas': None}), ('set_shards', {'shards': None}), ('set_replicas', {'replicas': None}), + ('add_replicas', {'replicas': None}), + ('remove_replicas', {'replicas': None}), )) def test_admin(admin_func_name, kwargs): from bigchaindb.backend import admin diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 1a1291e3..f61c4c6f 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -1,6 +1,6 @@ import json from unittest.mock import Mock, patch -from argparse import Namespace +from argparse import Namespace, ArgumentTypeError import copy import pytest @@ -376,3 +376,55 @@ def test_calling_main(start_mock, base_parser_mock, parse_args_mock, 'distributed equally to all ' 'the processes') assert start_mock.called is True + + +@patch('bigchaindb.backend.admin.add_replicas') +def test_run_add_replicas(mock_add_replicas): + from bigchaindb.commands.bigchain import run_add_replicas + from bigchaindb.backend.exceptions import DatabaseOpFailedError + + args = Namespace(config=None, replicas=['localhost:27017']) + + # test add_replicas no raises + mock_add_replicas.return_value = None + assert run_add_replicas(args) is None + + # test add_replicas with `DatabaseOpFailedError` + mock_add_replicas.side_effect = DatabaseOpFailedError() + assert run_add_replicas(args) is None + + # test add_replicas with `NotImplementedError` + mock_add_replicas.side_effect = NotImplementedError() + assert run_add_replicas(args) is None + + +@patch('bigchaindb.backend.admin.remove_replicas') +def test_run_remove_replicas(mock_remove_replicas): + from bigchaindb.commands.bigchain import run_remove_replicas + from bigchaindb.backend.exceptions import DatabaseOpFailedError + + args = Namespace(config=None, replicas=['localhost:27017']) + + # test add_replicas no raises + mock_remove_replicas.return_value = None + assert run_remove_replicas(args) is None + + # test add_replicas with `DatabaseOpFailedError` + mock_remove_replicas.side_effect = DatabaseOpFailedError() + assert run_remove_replicas(args) is None + + # test add_replicas with `NotImplementedError` + mock_remove_replicas.side_effect = NotImplementedError() + assert run_remove_replicas(args) is None + + +def test_mongodb_host_type(): + from bigchaindb.commands.utils import mongodb_host + + # bad port provided + with pytest.raises(ArgumentTypeError): + mongodb_host('localhost:11111111111') + + # no port information provided + with pytest.raises(ArgumentTypeError): + mongodb_host('localhost')