bigchaindb/tests/backend/localmongodb/test_connection.py

200 lines
7.2 KiB
Python
Raw Normal View History

# Copyright BigchainDB GmbH and BigchainDB contributors
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0
from unittest import mock
import pytest
2017-02-02 19:58:00 +01:00
import pymongo
from pymongo import MongoClient
from pymongo.database import Database
pytestmark = [pytest.mark.bdb, pytest.mark.tendermint]
@pytest.fixture
def mock_cmd_line_opts():
return {'argv': ['mongod', '--dbpath=/data'],
'ok': 1.0,
'parsed': {'replication': {'replSet': None},
'storage': {'dbPath': '/data'}}}
@pytest.fixture
def mock_config_opts():
return {'argv': ['mongod', '--dbpath=/data'],
'ok': 1.0,
'parsed': {'replication': {'replSetName': None},
'storage': {'dbPath': '/data'}}}
@pytest.fixture
def mongodb_connection():
import bigchaindb
return MongoClient(host=bigchaindb.config['database']['host'],
port=bigchaindb.config['database']['port'])
2016-12-19 13:29:14 +01:00
def test_get_connection_returns_the_correct_instance(db_host, db_port):
2016-12-19 13:29:14 +01:00
from bigchaindb.backend import connect
from bigchaindb.backend.connection import Connection
from bigchaindb.backend.localmongodb.connection import LocalMongoDBConnection
2016-12-19 13:29:14 +01:00
config = {
'backend': 'localmongodb',
'host': db_host,
'port': db_port,
'name': 'test',
'replicaset': None,
2016-12-19 13:29:14 +01:00
}
conn = connect(**config)
assert isinstance(conn, Connection)
assert isinstance(conn, LocalMongoDBConnection)
assert conn.conn._topology_settings.replica_set_name == config['replicaset']
@mock.patch('bigchaindb.backend.localmongodb.connection.initialize_replica_set')
@mock.patch('pymongo.MongoClient.__init__')
@mock.patch('time.sleep')
def test_connection_error(mock_sleep, mock_client, mock_init_repl_set):
from bigchaindb.backend import connect
2017-01-31 16:59:43 +01:00
from bigchaindb.backend.exceptions import ConnectionError
2017-02-02 19:18:47 +01:00
# force the driver to throw ConnectionFailure
# the mock on time.sleep is to prevent the actual sleep when running
# the tests
2017-02-02 19:58:00 +01:00
mock_client.side_effect = pymongo.errors.ConnectionFailure()
2017-01-31 16:59:43 +01:00
with pytest.raises(ConnectionError):
conn = connect()
conn.db
assert mock_client.call_count == 3
@mock.patch('bigchaindb.backend.localmongodb.connection.initialize_replica_set')
2017-02-02 19:58:00 +01:00
@mock.patch('pymongo.MongoClient')
def test_connection_run_errors(mock_client, mock_init_repl_set):
from bigchaindb.backend import connect
from bigchaindb.backend.exceptions import (DuplicateKeyError,
OperationError,
ConnectionError)
conn = connect()
2017-02-06 16:14:14 +01:00
query = mock.Mock()
2017-02-02 19:58:00 +01:00
query.run.side_effect = pymongo.errors.AutoReconnect('foo')
with pytest.raises(ConnectionError):
conn.run(query)
2017-02-06 16:14:14 +01:00
assert query.run.call_count == 2
2017-02-02 19:58:00 +01:00
2017-02-06 16:14:14 +01:00
query = mock.Mock()
2017-02-02 19:58:00 +01:00
query.run.side_effect = pymongo.errors.DuplicateKeyError('foo')
with pytest.raises(DuplicateKeyError):
conn.run(query)
2017-02-06 16:14:14 +01:00
assert query.run.call_count == 1
2017-02-02 19:58:00 +01:00
2017-02-06 16:14:14 +01:00
query = mock.Mock()
2017-02-02 19:58:00 +01:00
query.run.side_effect = pymongo.errors.OperationFailure('foo')
with pytest.raises(OperationError):
conn.run(query)
2017-02-06 16:14:14 +01:00
assert query.run.call_count == 1
2017-02-02 19:58:00 +01:00
2017-03-28 11:24:16 +02:00
@mock.patch('pymongo.database.Database.authenticate')
def test_connection_with_credentials(mock_authenticate):
import bigchaindb
from bigchaindb.backend.localmongodb.connection import LocalMongoDBConnection
conn = LocalMongoDBConnection(host=bigchaindb.config['database']['host'],
port=bigchaindb.config['database']['port'],
login='theplague',
password='secret')
2017-03-28 11:24:16 +02:00
conn.connect()
assert mock_authenticate.call_count == 1
2017-03-28 11:24:16 +02:00
def test_check_replica_set_not_enabled(mongodb_connection):
from bigchaindb.backend.localmongodb.connection import _check_replica_set
from bigchaindb.common.exceptions import ConfigurationError
# no replSet option set
cmd_line_opts = {'argv': ['mongod', '--dbpath=/data'],
'ok': 1.0,
'parsed': {'storage': {'dbPath': '/data'}}}
with mock.patch.object(Database, 'command', return_value=cmd_line_opts):
with pytest.raises(ConfigurationError):
_check_replica_set(mongodb_connection)
def test_check_replica_set_command_line(mongodb_connection,
mock_cmd_line_opts):
from bigchaindb.backend.localmongodb.connection import _check_replica_set
# replSet option set through the command line
with mock.patch.object(Database, 'command',
return_value=mock_cmd_line_opts):
assert _check_replica_set(mongodb_connection) is None
def test_check_replica_set_config_file(mongodb_connection, mock_config_opts):
from bigchaindb.backend.localmongodb.connection import _check_replica_set
# replSet option set through the config file
with mock.patch.object(Database, 'command', return_value=mock_config_opts):
assert _check_replica_set(mongodb_connection) is None
def test_check_replica_set_name_mismatch(mongodb_connection,
mock_cmd_line_opts):
from bigchaindb.backend.localmongodb.connection import _check_replica_set
from bigchaindb.common.exceptions import ConfigurationError
# change the replica set name so it does not match the bigchaindb config
mock_cmd_line_opts['parsed']['replication']['replSet'] = 'rs0'
with mock.patch.object(Database, 'command',
return_value=mock_cmd_line_opts):
with pytest.raises(ConfigurationError):
_check_replica_set(mongodb_connection)
def test_wait_for_replica_set_initialization(mongodb_connection):
from bigchaindb.backend.localmongodb.connection import _wait_for_replica_set_initialization # noqa
with mock.patch.object(Database, 'command') as mock_command:
mock_command.side_effect = [
{'log': ['a line']},
{'log': ['database writes are now permitted']},
]
# check that it returns
assert _wait_for_replica_set_initialization(mongodb_connection) is None
def test_initialize_replica_set(mock_cmd_line_opts):
from bigchaindb.backend.localmongodb.connection import initialize_replica_set
with mock.patch.object(Database, 'command') as mock_command:
mock_command.side_effect = [
mock_cmd_line_opts,
None,
{'log': ['database writes are now permitted']},
]
# check that it returns
assert initialize_replica_set('host', 1337, 1000, 'dbname', False, None, None,
None, None, None, None, None) is None
# test it raises OperationError if anything wrong
with mock.patch.object(Database, 'command') as mock_command:
mock_command.side_effect = [
mock_cmd_line_opts,
2017-02-02 19:58:00 +01:00
pymongo.errors.OperationFailure(None, details={'codeName': ''})
]
2017-02-02 19:58:00 +01:00
with pytest.raises(pymongo.errors.OperationFailure):
initialize_replica_set('host', 1337, 1000, 'dbname', False, None,
None, None, None, None, None, None) is None