diff --git a/bigchaindb/__init__.py b/bigchaindb/__init__.py index c50f4810..315774e5 100644 --- a/bigchaindb/__init__.py +++ b/bigchaindb/__init__.py @@ -5,6 +5,20 @@ import os # PORT_NUMBER = reduce(lambda x, y: x * y, map(ord, 'BigchainDB')) % 2**16 # basically, the port number is 9984 +_database_rethinkdb = { + 'backend': os.environ.get('BIGCHAINDB_DATABASE_BACKEND', 'rethinkdb'), + 'host': os.environ.get('BIGCHAINDB_DATABASE_HOST', 'localhost'), + 'port': int(os.environ.get('BIGCHAINDB_DATABASE_PORT', 28015)), + 'name': os.environ.get('BIGCHAINDB_DATABASE_NAME', 'bigchain'), +} + +_database_mongodb = { + 'backend': os.environ.get('BIGCHAINDB_DATABASE_BACKEND', 'mongodb'), + 'host': os.environ.get('BIGCHAINDB_DATABASE_HOST', 'localhost'), + 'port': int(os.environ.get('BIGCHAINDB_DATABASE_PORT', 27017)), + 'name': os.environ.get('BIGCHAINDB_DATABASE_NAME', 'bigchain'), + 'replicaset': os.environ.get('BIGCHAINDB_DATABASE_REPLICASET', 'bigchain-rs'), +} config = { 'server': { @@ -14,13 +28,7 @@ config = { 'workers': None, # if none, the value will be cpu_count * 2 + 1 'threads': None, # if none, the value will be cpu_count * 2 + 1 }, - 'database': { - 'backend': os.environ.get('BIGCHAINDB_DATABASE_BACKEND', 'rethinkdb'), - 'host': os.environ.get('BIGCHAINDB_DATABASE_HOST', 'localhost'), - 'port': int(os.environ.get('BIGCHAINDB_DATABASE_PORT', 28015)), - 'name': os.environ.get('BIGCHAINDB_DATABASE_NAME', 'bigchain'), - 'replicaset': os.environ.get('BIGCHAINDB_DATABASE_REPLICASET', 'bigchain-rs'), - }, + 'database': _database_rethinkdb, 'keypair': { 'public': None, 'private': None, diff --git a/bigchaindb/commands/bigchain.py b/bigchaindb/commands/bigchain.py index 6661e902..2fc8df70 100644 --- a/bigchaindb/commands/bigchain.py +++ b/bigchaindb/commands/bigchain.py @@ -86,6 +86,16 @@ def run_configure(args, skip_if_exists=False): conf['keypair']['private'], conf['keypair']['public'] = \ crypto.generate_key_pair() + # select the correct config defaults based on the backend + print('Generating default configuration for backend {}' + .format(args.backend)) + database = {} + if args.backend == 'rethinkdb': + database = bigchaindb._database_rethinkdb + elif args.backend == 'mongodb': + database = bigchaindb._database_mongodb + conf['database'] = database + if not args.yes: for key in ('bind', ): val = conf['server'][key] @@ -282,9 +292,13 @@ def create_parser(): dest='command') # parser for writing a config file - subparsers.add_parser('configure', - help='Prepare the config file ' - 'and create the node keypair') + config_parser = subparsers.add_parser('configure', + help='Prepare the config file ' + 'and create the node keypair') + config_parser.add_argument('backend', + choices=['rethinkdb', 'mongodb'], + help='The backend to use. It can be either ' + 'rethinkdb or mongodb.') # parsers for showing/exporting config values subparsers.add_parser('show-config', diff --git a/tests/backend/test_generics.py b/tests/backend/test_generics.py index 2ab33a7c..2049d72b 100644 --- a/tests/backend/test_generics.py +++ b/tests/backend/test_generics.py @@ -1,4 +1,3 @@ -from importlib import import_module from unittest.mock import patch from pytest import mark, raises @@ -69,10 +68,6 @@ def test_changefeed_class(changefeed_class_func_name, args_qty): changefeed_class_func(None, *range(args_qty)) -@mark.parametrize('db,conn_cls', ( - ('mongodb', 'MongoDBConnection'), - ('rethinkdb', 'RethinkDBConnection'), -)) @patch('bigchaindb.backend.schema.create_indexes', autospec=True, return_value=None) @patch('bigchaindb.backend.schema.create_tables', @@ -80,16 +75,24 @@ def test_changefeed_class(changefeed_class_func_name, args_qty): @patch('bigchaindb.backend.schema.create_database', autospec=True, return_value=None) def test_init_database(mock_create_database, mock_create_tables, - mock_create_indexes, db, conn_cls): + mock_create_indexes): from bigchaindb.backend.schema import init_database - conn = getattr( - import_module('bigchaindb.backend.{}.connection'.format(db)), - conn_cls, - )('host', 'port', 'dbname') + from bigchaindb.backend.rethinkdb.connection import RethinkDBConnection + from bigchaindb.backend.mongodb.connection import MongoDBConnection + + # rethinkdb + conn = RethinkDBConnection('host', 'port', 'dbname') init_database(connection=conn, dbname='mickeymouse') - mock_create_database.assert_called_once_with(conn, 'mickeymouse') - mock_create_tables.assert_called_once_with(conn, 'mickeymouse') - mock_create_indexes.assert_called_once_with(conn, 'mickeymouse') + mock_create_database.assert_called_with(conn, 'mickeymouse') + mock_create_tables.assert_called_with(conn, 'mickeymouse') + mock_create_indexes.assert_called_with(conn, 'mickeymouse') + + # mongodb + conn = MongoDBConnection('host', 'port', 'dbname', replicaset='rs') + init_database(connection=conn, dbname='mickeymouse') + mock_create_database.assert_called_with(conn, 'mickeymouse') + mock_create_tables.assert_called_with(conn, 'mickeymouse') + mock_create_indexes.assert_called_with(conn, 'mickeymouse') @mark.parametrize('admin_func_name,kwargs', ( diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index a2e485da..1a1291e3 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -12,7 +12,8 @@ def test_make_sure_we_dont_remove_any_command(): parser = create_parser() - assert parser.parse_args(['configure']).command + assert parser.parse_args(['configure', 'rethinkdb']).command + assert parser.parse_args(['configure', 'mongodb']).command assert parser.parse_args(['show-config']).command assert parser.parse_args(['export-my-pubkey']).command assert parser.parse_args(['init']).command @@ -31,8 +32,8 @@ def test_start_raises_if_command_not_implemented(): with pytest.raises(NotImplementedError): # Will raise because `scope`, the third parameter, - # doesn't contain the function `run_configure` - utils.start(parser, ['configure'], {}) + # doesn't contain the function `run_start` + utils.start(parser, ['start'], {}) def test_start_raises_if_no_arguments_given(): @@ -204,7 +205,7 @@ def test_run_configure_when_config_does_not_exist(monkeypatch, from bigchaindb.commands.bigchain import run_configure monkeypatch.setattr('os.path.exists', lambda path: False) monkeypatch.setattr('builtins.input', lambda: '\n') - args = Namespace(config='foo', yes=True) + args = Namespace(config='foo', backend='rethinkdb', yes=True) return_value = run_configure(args) assert return_value is None @@ -228,6 +229,36 @@ def test_run_configure_when_config_does_exist(monkeypatch, assert value == {} +@pytest.mark.parametrize('backend', ( + 'rethinkdb', + 'mongodb', +)) +def test_run_configure_with_backend(backend, monkeypatch, mock_write_config): + import bigchaindb + from bigchaindb.commands.bigchain import run_configure + + value = {} + + def mock_write_config(new_config, filename=None): + value['return'] = new_config + + monkeypatch.setattr('os.path.exists', lambda path: False) + monkeypatch.setattr('builtins.input', lambda: '\n') + monkeypatch.setattr('bigchaindb.config_utils.write_config', + mock_write_config) + + args = Namespace(config='foo', backend=backend, yes=True) + expected_config = bigchaindb.config + run_configure(args) + + # update the expected config with the correct backend and keypair + backend_conf = getattr(bigchaindb, '_database_' + backend) + expected_config.update({'database': backend_conf, + 'keypair': value['return']['keypair']}) + + assert value['return'] == expected_config + + @patch('bigchaindb.common.crypto.generate_key_pair', return_value=('private_key', 'public_key')) @pytest.mark.usefixtures('ignore_local_config_file') diff --git a/tests/conftest.py b/tests/conftest.py index a69564bc..c3177c14 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -109,26 +109,24 @@ def _restore_dbs(request): @pytest.fixture(scope='session') def _configure_bigchaindb(request): + import bigchaindb from bigchaindb import config_utils test_db_name = TEST_DB_NAME # Put a suffix like _gw0, _gw1 etc on xdist processes xdist_suffix = getattr(request.config, 'slaveinput', {}).get('slaveid') if xdist_suffix: test_db_name = '{}_{}'.format(TEST_DB_NAME, xdist_suffix) + + backend = request.config.getoption('--database-backend') + backend_conf = getattr(bigchaindb, '_database_' + backend) config = { - 'database': { - 'name': test_db_name, - 'backend': request.config.getoption('--database-backend'), - }, + 'database': backend_conf, 'keypair': { 'private': '31Lb1ZGKTyHnmVK3LUMrAUrPNfd4sE2YyBt3UA4A25aA', 'public': '4XYfCbabAWVUCbjTmRTFEu2sc3dFEdkse4r6X498B1s8', } } - # FIXME - if config['database']['backend'] == 'mongodb': - # not a great way to do this - config['database']['port'] = 27017 + config['database']['name'] = test_db_name config_utils.set_config(config) diff --git a/tests/test_config_utils.py b/tests/test_config_utils.py index 6328d28c..4cb8bd45 100644 --- a/tests/test_config_utils.py +++ b/tests/test_config_utils.py @@ -130,7 +130,6 @@ def test_autoconfigure_read_both_from_file_and_env(monkeypatch, request): 'host': 'test-host', 'port': 4242, 'name': 'test-dbname', - 'replicaset': 'bigchain-rs' }, 'keypair': { 'public': None, @@ -215,7 +214,6 @@ def test_write_config(): ('BIGCHAINDB_DATABASE_HOST', 'test-host', 'host'), ('BIGCHAINDB_DATABASE_PORT', 4242, 'port'), ('BIGCHAINDB_DATABASE_NAME', 'test-db', 'name'), - ('BIGCHAINDB_DATABASE_REPLICASET', 'test-replicaset', 'replicaset') )) def test_database_envs(env_name, env_value, config_key, monkeypatch): import bigchaindb @@ -227,3 +225,18 @@ def test_database_envs(env_name, env_value, config_key, monkeypatch): expected_config['database'][config_key] = env_value assert bigchaindb.config == expected_config + + +def test_database_envs_replicaset(monkeypatch): + # the replica set env is only used if the backend is mongodb + import bigchaindb + + monkeypatch.setattr('os.environ', {'BIGCHAINDB_DATABASE_REPLICASET': + 'test-replicaset'}) + bigchaindb.config['database'] = bigchaindb._database_mongodb + bigchaindb.config_utils.autoconfigure() + + expected_config = copy.deepcopy(bigchaindb.config) + expected_config['database']['replicaset'] = 'test-replicaset' + + assert bigchaindb.config == expected_config