mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Problem: Migrate-CLI changes were reverted because of travis changes (#2121)
* Testing tendermint docker compose for travis * Typo tendermint* * Re-do migrate cli changes * don't skip event stream test * Fix flake8 and unskip a test skipped during dev * Revert styling changes made from editor * skip a failing test case which was already disabled * Remove reference to 'keypair' in commands
This commit is contained in:
parent
60f2ccaead
commit
f537d061d5
@ -9,23 +9,13 @@ import copy
|
||||
import json
|
||||
import sys
|
||||
|
||||
from bigchaindb.common import crypto
|
||||
from bigchaindb.common.exceptions import (StartupError,
|
||||
DatabaseAlreadyExists,
|
||||
KeypairNotFoundException,
|
||||
from bigchaindb.common.exceptions import (DatabaseAlreadyExists,
|
||||
DatabaseDoesNotExist)
|
||||
import bigchaindb
|
||||
from bigchaindb import backend
|
||||
from bigchaindb.backend import schema
|
||||
from bigchaindb.backend import query
|
||||
from bigchaindb.backend.admin import (set_replicas, set_shards, add_replicas,
|
||||
remove_replicas)
|
||||
from bigchaindb.backend.exceptions import OperationError
|
||||
from bigchaindb.commands import utils
|
||||
from bigchaindb.commands.messages import (
|
||||
CANNOT_START_KEYPAIR_NOT_FOUND,
|
||||
RETHINKDB_STARTUP_ERROR,
|
||||
)
|
||||
from bigchaindb.commands.utils import (
|
||||
configure_bigchaindb, start_logging_process, input_on_stderr)
|
||||
|
||||
@ -53,12 +43,9 @@ def run_show_config(args):
|
||||
print(json.dumps(config, indent=4, sort_keys=True))
|
||||
|
||||
|
||||
def run_configure(args, skip_if_exists=False):
|
||||
"""Run a script to configure the current node.
|
||||
|
||||
Args:
|
||||
skip_if_exists (bool): skip the function if a config file already exists
|
||||
"""
|
||||
@configure_bigchaindb
|
||||
def run_configure(args):
|
||||
"""Run a script to configure the current node."""
|
||||
config_path = args.config or bigchaindb.config_utils.CONFIG_DEFAULT_PATH
|
||||
|
||||
config_file_exists = False
|
||||
@ -66,9 +53,6 @@ def run_configure(args, skip_if_exists=False):
|
||||
if config_path != '-':
|
||||
config_file_exists = os.path.exists(config_path)
|
||||
|
||||
if config_file_exists and skip_if_exists:
|
||||
return
|
||||
|
||||
if config_file_exists and not args.yes:
|
||||
want = input_on_stderr('Config file `{}` exists, do you want to '
|
||||
'override it? (cannot be undone) [y/N]: '.format(config_path))
|
||||
@ -77,15 +61,6 @@ def run_configure(args, skip_if_exists=False):
|
||||
|
||||
conf = copy.deepcopy(bigchaindb.config)
|
||||
|
||||
# Patch the default configuration with the new values
|
||||
conf = bigchaindb.config_utils.update(
|
||||
conf,
|
||||
bigchaindb.config_utils.env_config(bigchaindb.config))
|
||||
|
||||
print('Generating keypair', file=sys.stderr)
|
||||
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), file=sys.stderr)
|
||||
@ -117,23 +92,7 @@ def run_configure(args, skip_if_exists=False):
|
||||
print('Ready to go!', file=sys.stderr)
|
||||
|
||||
|
||||
@configure_bigchaindb
|
||||
def run_export_my_pubkey(args):
|
||||
"""Export this node's public key to standard output
|
||||
"""
|
||||
pubkey = bigchaindb.config['keypair']['public']
|
||||
if pubkey is not None:
|
||||
print(pubkey)
|
||||
else:
|
||||
sys.exit("This node's public key wasn't set anywhere "
|
||||
"so it can't be exported")
|
||||
# raises SystemExit exception
|
||||
# message is sent to stderr
|
||||
# exits with exit code 1 (signals tha an error happened)
|
||||
|
||||
|
||||
def _run_init():
|
||||
# Try to access the keypair, throws an exception if it does not exist
|
||||
b = bigchaindb.Bigchain()
|
||||
|
||||
schema.init_database(connection=b.connection)
|
||||
@ -194,82 +153,18 @@ def run_start(args):
|
||||
|
||||
# run_recover(BigchainDB())
|
||||
|
||||
if args.allow_temp_keypair:
|
||||
if not (bigchaindb.config['keypair']['private'] or
|
||||
bigchaindb.config['keypair']['public']):
|
||||
|
||||
private_key, public_key = crypto.generate_key_pair()
|
||||
bigchaindb.config['keypair']['private'] = private_key
|
||||
bigchaindb.config['keypair']['public'] = public_key
|
||||
else:
|
||||
logger.warning('Keypair found, no need to create one on the fly.')
|
||||
|
||||
if args.start_rethinkdb:
|
||||
try:
|
||||
proc = utils.start_rethinkdb()
|
||||
except StartupError as e:
|
||||
sys.exit(RETHINKDB_STARTUP_ERROR.format(e))
|
||||
logger.info('RethinkDB started with PID %s' % proc.pid)
|
||||
|
||||
try:
|
||||
if not args.skip_initialize_database:
|
||||
logger.info('Initializing database')
|
||||
_run_init()
|
||||
except DatabaseAlreadyExists:
|
||||
pass
|
||||
except KeypairNotFoundException:
|
||||
sys.exit(CANNOT_START_KEYPAIR_NOT_FOUND)
|
||||
|
||||
logger.info('Starting BigchainDB main process with public key %s',
|
||||
bigchaindb.config['keypair']['public'])
|
||||
logger.info('Starting BigchainDB main process.')
|
||||
from bigchaindb.tendermint.commands import start
|
||||
start()
|
||||
|
||||
|
||||
@configure_bigchaindb
|
||||
def run_set_shards(args):
|
||||
conn = backend.connect()
|
||||
try:
|
||||
set_shards(conn, shards=args.num_shards)
|
||||
except OperationError as e:
|
||||
sys.exit(str(e))
|
||||
|
||||
|
||||
@configure_bigchaindb
|
||||
def run_set_replicas(args):
|
||||
conn = backend.connect()
|
||||
try:
|
||||
set_replicas(conn, replicas=args.num_replicas)
|
||||
except OperationError as e:
|
||||
sys.exit(str(e))
|
||||
|
||||
|
||||
@configure_bigchaindb
|
||||
def run_add_replicas(args):
|
||||
# Note: This command is specific to MongoDB
|
||||
conn = backend.connect()
|
||||
|
||||
try:
|
||||
add_replicas(conn, args.replicas)
|
||||
except (OperationError, NotImplementedError) as e:
|
||||
sys.exit(str(e))
|
||||
else:
|
||||
print('Added {} to the replicaset.'.format(args.replicas))
|
||||
|
||||
|
||||
@configure_bigchaindb
|
||||
def run_remove_replicas(args):
|
||||
# Note: This command is specific to MongoDB
|
||||
conn = backend.connect()
|
||||
|
||||
try:
|
||||
remove_replicas(conn, args.replicas)
|
||||
except (OperationError, NotImplementedError) as e:
|
||||
sys.exit(str(e))
|
||||
else:
|
||||
print('Removed {} from the replicaset.'.format(args.replicas))
|
||||
|
||||
|
||||
def create_parser():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Control your BigchainDB node.',
|
||||
@ -284,23 +179,19 @@ def create_parser():
|
||||
|
||||
# parser for writing a config file
|
||||
config_parser = subparsers.add_parser('configure',
|
||||
help='Prepare the config file '
|
||||
'and create the node keypair')
|
||||
help='Prepare the config file.')
|
||||
config_parser.add_argument('backend',
|
||||
choices=['localmongodb'],
|
||||
default='localmongodb',
|
||||
const='localmongodb',
|
||||
nargs='?',
|
||||
help='The backend to use. It can be either '
|
||||
'rethinkdb or mongodb.')
|
||||
help='The backend to use. It can only be '
|
||||
'"localmongodb", currently.')
|
||||
|
||||
# parsers for showing/exporting config values
|
||||
subparsers.add_parser('show-config',
|
||||
help='Show the current configuration')
|
||||
|
||||
subparsers.add_parser('export-my-pubkey',
|
||||
help="Export this node's public key")
|
||||
|
||||
# parser for database-level commands
|
||||
subparsers.add_parser('init',
|
||||
help='Init the database')
|
||||
@ -312,63 +203,12 @@ def create_parser():
|
||||
start_parser = subparsers.add_parser('start',
|
||||
help='Start BigchainDB')
|
||||
|
||||
start_parser.add_argument('--dev-allow-temp-keypair',
|
||||
dest='allow_temp_keypair',
|
||||
action='store_true',
|
||||
help='Generate a random keypair on start')
|
||||
|
||||
start_parser.add_argument('--dev-start-rethinkdb',
|
||||
dest='start_rethinkdb',
|
||||
action='store_true',
|
||||
help='Run RethinkDB on start')
|
||||
|
||||
start_parser.add_argument('--no-init',
|
||||
dest='skip_initialize_database',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='Skip database initialization')
|
||||
|
||||
# parser for configuring the number of shards
|
||||
sharding_parser = subparsers.add_parser('set-shards',
|
||||
help='Configure number of shards')
|
||||
|
||||
sharding_parser.add_argument('num_shards', metavar='num_shards',
|
||||
type=int, default=1,
|
||||
help='Number of shards')
|
||||
|
||||
# parser for configuring the number of replicas
|
||||
replicas_parser = subparsers.add_parser('set-replicas',
|
||||
help='Configure number of replicas')
|
||||
|
||||
replicas_parser.add_argument('num_replicas', metavar='num_replicas',
|
||||
type=int, default=1,
|
||||
help='Number of replicas (i.e. the replication factor)')
|
||||
|
||||
# parser for adding nodes to the replica set
|
||||
add_replicas_parser = subparsers.add_parser('add-replicas',
|
||||
help='Add a set of nodes to the '
|
||||
'replica set. This command '
|
||||
'is specific to the MongoDB'
|
||||
' backend.')
|
||||
|
||||
add_replicas_parser.add_argument('replicas', nargs='+',
|
||||
type=utils.mongodb_host,
|
||||
help='A list of space separated hosts to '
|
||||
'add to the replicaset. Each host '
|
||||
'should be in the form `host:port`.')
|
||||
|
||||
# parser for removing nodes from the replica set
|
||||
rm_replicas_parser = subparsers.add_parser('remove-replicas',
|
||||
help='Remove a set of nodes from the '
|
||||
'replica set. This command '
|
||||
'is specific to the MongoDB'
|
||||
' backend.')
|
||||
|
||||
rm_replicas_parser.add_argument('replicas', nargs='+',
|
||||
type=utils.mongodb_host,
|
||||
help='A list of space separated hosts to '
|
||||
'remove from the replicaset. Each host '
|
||||
'should be in the form `host:port`.')
|
||||
return parser
|
||||
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
"""Module to store messages used in commands, such as error messages,
|
||||
warnings, prompts, etc.
|
||||
|
||||
"""
|
||||
CANNOT_START_KEYPAIR_NOT_FOUND = (
|
||||
"Can't start BigchainDB, no keypair found. "
|
||||
'Did you run `bigchaindb configure`?'
|
||||
)
|
||||
|
||||
RETHINKDB_STARTUP_ERROR = 'Error starting RethinkDB, reason is: {}'
|
@ -6,16 +6,10 @@ import argparse
|
||||
import builtins
|
||||
import functools
|
||||
import multiprocessing as mp
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import rethinkdb as r
|
||||
from pymongo import uri_parser
|
||||
|
||||
import bigchaindb
|
||||
import bigchaindb.config_utils
|
||||
from bigchaindb import backend
|
||||
from bigchaindb.common.exceptions import StartupError
|
||||
from bigchaindb.log.setup import setup_logging
|
||||
from bigchaindb.version import __version__
|
||||
|
||||
@ -125,46 +119,6 @@ def input_on_stderr(prompt='', default=None, convert=None):
|
||||
return _convert(value, default, convert)
|
||||
|
||||
|
||||
def start_rethinkdb():
|
||||
"""Start RethinkDB as a child process and wait for it to be
|
||||
available.
|
||||
|
||||
Raises:
|
||||
:class:`~bigchaindb.common.exceptions.StartupError` if
|
||||
RethinkDB cannot be started.
|
||||
"""
|
||||
|
||||
proc = subprocess.Popen(['rethinkdb', '--bind', 'all'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True)
|
||||
|
||||
dbname = bigchaindb.config['database']['name']
|
||||
line = ''
|
||||
|
||||
for line in proc.stdout:
|
||||
if line.startswith('Server ready'):
|
||||
|
||||
# FIXME: seems like tables are not ready when the server is ready,
|
||||
# that's why we need to query RethinkDB to know the state
|
||||
# of the database. This code assumes the tables are ready
|
||||
# when the database is ready. This seems a valid assumption.
|
||||
try:
|
||||
conn = backend.connect()
|
||||
# Before checking if the db is ready, we need to query
|
||||
# the server to check if it contains that db
|
||||
if conn.run(r.db_list().contains(dbname)):
|
||||
conn.run(r.db(dbname).wait())
|
||||
except (r.ReqlOpFailedError, r.ReqlDriverError) as exc:
|
||||
raise StartupError('Error waiting for the database `{}` '
|
||||
'to be ready'.format(dbname)) from exc
|
||||
return proc
|
||||
|
||||
# We are here when we exhaust the stdout of the process.
|
||||
# The last `line` contains info about the error.
|
||||
raise StartupError(line)
|
||||
|
||||
|
||||
def start(parser, argv, scope):
|
||||
"""Utility function to execute a subcommand.
|
||||
|
||||
@ -206,34 +160,6 @@ def start(parser, argv, scope):
|
||||
return func(args)
|
||||
|
||||
|
||||
def mongodb_host(host):
|
||||
"""Utility function that works as a type for mongodb ``host`` args.
|
||||
|
||||
This function validates the ``host`` args provided by to the
|
||||
``add-replicas`` and ``remove-replicas`` commands and checks if each arg
|
||||
is in the form "host:port"
|
||||
|
||||
Args:
|
||||
host (str): A string containing hostname and port (e.g. "host:port")
|
||||
|
||||
Raises:
|
||||
ArgumentTypeError: if it fails to parse the argument
|
||||
"""
|
||||
# check if mongodb can parse the host
|
||||
try:
|
||||
hostname, port = uri_parser.parse_host(host, default_port=None)
|
||||
except ValueError as exc:
|
||||
raise argparse.ArgumentTypeError(exc.args[0])
|
||||
|
||||
# we do require the port to be provided.
|
||||
if port is None or hostname == '':
|
||||
raise argparse.ArgumentTypeError('expected host in the form '
|
||||
'`host:port`. Got `{}` instead.'
|
||||
.format(host))
|
||||
|
||||
return host
|
||||
|
||||
|
||||
base_parser = argparse.ArgumentParser(add_help=False, prog='bigchaindb')
|
||||
|
||||
base_parser.add_argument('-c', '--config',
|
||||
|
@ -68,8 +68,8 @@ class Bigchain(object):
|
||||
self.consensus = BaseConsensusRules
|
||||
|
||||
self.connection = connection if connection else backend.connect(**bigchaindb.config['database'])
|
||||
if not self.me or not self.me_private:
|
||||
raise exceptions.KeypairNotFoundException()
|
||||
# if not self.me:
|
||||
# raise exceptions.KeypairNotFoundException()
|
||||
|
||||
federation = property(lambda self: set(self.nodes_except_me + [self.me]))
|
||||
""" Set of federation member public keys """
|
||||
|
@ -47,8 +47,6 @@ def run_start_args(request):
|
||||
param = getattr(request, 'param', {})
|
||||
return Namespace(
|
||||
config=param.get('config'),
|
||||
start_rethinkdb=param.get('start_rethinkdb', False),
|
||||
allow_temp_keypair=param.get('allow_temp_keypair', False),
|
||||
skip_initialize_database=param.get('skip_initialize_database', False),
|
||||
)
|
||||
|
||||
|
@ -1,125 +0,0 @@
|
||||
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,
|
||||
mocked_setup_logging):
|
||||
from bigchaindb import config
|
||||
from bigchaindb.commands.bigchaindb import run_start
|
||||
args = Namespace(start_rethinkdb=True, allow_temp_keypair=False, config=None, yes=True,
|
||||
skip_initialize_database=False)
|
||||
run_start(args)
|
||||
|
||||
mock_start_rethinkdb.assert_called_with()
|
||||
mocked_setup_logging.assert_called_once_with(user_log_config=config['log'])
|
||||
|
||||
|
||||
@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.bigchaindb 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, config=None)
|
||||
run_set_shards(args)
|
||||
mock_reconfigure.assert_called_with(replicas=1, shards=3, dry_run=False)
|
||||
|
||||
# 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, dry_run=False)
|
||||
|
||||
|
||||
def test_set_shards_raises_exception(monkeypatch, b):
|
||||
from bigchaindb.commands.bigchaindb 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, config=None)
|
||||
with pytest.raises(SystemExit) as exc:
|
||||
run_set_shards(args)
|
||||
assert exc.value.args == ('Failed to reconfigure tables.',)
|
||||
|
||||
|
||||
@patch('rethinkdb.ast.Table.reconfigure')
|
||||
def test_set_replicas(mock_reconfigure, monkeypatch, b):
|
||||
from bigchaindb.commands.bigchaindb 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, config=None)
|
||||
run_set_replicas(args)
|
||||
mock_reconfigure.assert_called_with(replicas=2, shards=2, dry_run=False)
|
||||
|
||||
# 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, dry_run=False)
|
||||
|
||||
|
||||
def test_set_replicas_raises_exception(monkeypatch, b):
|
||||
from bigchaindb.commands.bigchaindb 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, config=None)
|
||||
with pytest.raises(SystemExit) as exc:
|
||||
run_set_replicas(args)
|
||||
assert exc.value.args == ('Failed to reconfigure tables.',)
|
@ -1,7 +1,6 @@
|
||||
import json
|
||||
from unittest.mock import Mock, patch
|
||||
from argparse import Namespace
|
||||
import copy
|
||||
|
||||
import pytest
|
||||
|
||||
@ -13,19 +12,14 @@ def test_make_sure_we_dont_remove_any_command():
|
||||
|
||||
parser = create_parser()
|
||||
|
||||
assert parser.parse_args(['configure', 'localmongodb']).command
|
||||
assert parser.parse_args(['configure', 'localmongodb']).command
|
||||
assert parser.parse_args(['show-config']).command
|
||||
assert parser.parse_args(['export-my-pubkey']).command
|
||||
assert parser.parse_args(['init']).command
|
||||
assert parser.parse_args(['drop']).command
|
||||
assert parser.parse_args(['start']).command
|
||||
assert parser.parse_args(['set-shards', '1']).command
|
||||
assert parser.parse_args(['set-replicas', '1']).command
|
||||
assert parser.parse_args(['add-replicas', 'localhost:27017']).command
|
||||
assert parser.parse_args(['remove-replicas', 'localhost:27017']).command
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
@patch('bigchaindb.commands.utils.start')
|
||||
def test_main_entrypoint(mock_start):
|
||||
from bigchaindb.commands.bigchaindb import main
|
||||
@ -40,95 +34,38 @@ def test_bigchain_run_start(mock_run_configure,
|
||||
mocked_setup_logging):
|
||||
from bigchaindb import config
|
||||
from bigchaindb.commands.bigchaindb import run_start
|
||||
args = Namespace(start_rethinkdb=False, allow_temp_keypair=False, config=None, yes=True,
|
||||
args = Namespace(config=None, yes=True,
|
||||
skip_initialize_database=False)
|
||||
run_start(args)
|
||||
mocked_setup_logging.assert_called_once_with(user_log_config=config['log'])
|
||||
|
||||
|
||||
@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, mocked_setup_logging):
|
||||
import bigchaindb
|
||||
from bigchaindb.commands.bigchaindb import run_start
|
||||
from bigchaindb import config_utils
|
||||
|
||||
value = {}
|
||||
expected_config = copy.deepcopy(bigchaindb._config)
|
||||
expected_config['keypair']['public'] = 'pubkey'
|
||||
expected_config['keypair']['private'] = 'privkey'
|
||||
|
||||
def mock_write_config(newconfig, filename=None):
|
||||
value['return'] = newconfig
|
||||
|
||||
monkeypatch.setattr(config_utils, 'write_config', mock_write_config)
|
||||
monkeypatch.setattr(config_utils, 'file_config', lambda x: config_utils.set_config(expected_config))
|
||||
monkeypatch.setattr('os.path.exists', lambda path: False)
|
||||
|
||||
args = Namespace(config=None, yes=True)
|
||||
run_start(args)
|
||||
|
||||
mocked_setup_logging.assert_called_once_with()
|
||||
assert value['return'] == expected_config
|
||||
|
||||
|
||||
# TODO Please beware, that if debugging, the "-s" switch for pytest will
|
||||
# interfere with capsys.
|
||||
# See related issue: https://github.com/pytest-dev/pytest/issues/128
|
||||
@pytest.mark.tendermint
|
||||
@pytest.mark.usefixtures('ignore_local_config_file')
|
||||
def test_bigchain_show_config(capsys):
|
||||
from bigchaindb import config
|
||||
from bigchaindb.commands.bigchaindb import run_show_config
|
||||
|
||||
args = Namespace(config=None)
|
||||
_, _ = capsys.readouterr()
|
||||
run_show_config(args)
|
||||
output_config = json.loads(capsys.readouterr()[0])
|
||||
# Note: This test passed previously because we were always
|
||||
# using the default configuration parameters, but since we
|
||||
# are running with docker-compose now and expose parameters like
|
||||
# BIGCHAINDB_SERVER_BIND, BIGCHAINDB_WSSERVER_HOST, BIGCHAINDB_WSSERVER_ADVERTISED_HOST
|
||||
# the default comparison fails i.e. when config is imported at the beginning the
|
||||
# dict returned is different that what is expected after run_show_config
|
||||
# and run_show_config updates the bigchaindb.config
|
||||
from bigchaindb import config
|
||||
del config['CONFIGURED']
|
||||
config['keypair']['private'] = 'x' * 45
|
||||
assert output_config == config
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('ignore_local_config_file')
|
||||
def test_bigchain_export_my_pubkey_when_pubkey_set(capsys, monkeypatch):
|
||||
from bigchaindb import config
|
||||
from bigchaindb.commands.bigchaindb import run_export_my_pubkey
|
||||
|
||||
args = Namespace(config=None)
|
||||
# so in run_export_my_pubkey(args) below,
|
||||
# filename=args.config='dummy' is passed to autoconfigure().
|
||||
# We just assume autoconfigure() works and sets
|
||||
# config['keypair']['public'] correctly (tested elsewhere).
|
||||
# We force-set config['keypair']['public'] using monkeypatch.
|
||||
monkeypatch.setitem(config['keypair'], 'public', 'Charlie_Bucket')
|
||||
_, _ = capsys.readouterr() # has the effect of clearing capsys
|
||||
run_export_my_pubkey(args)
|
||||
out, _ = capsys.readouterr()
|
||||
lines = out.splitlines()
|
||||
assert config['keypair']['public'] in lines
|
||||
assert 'Charlie_Bucket' in lines
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('ignore_local_config_file')
|
||||
def test_bigchain_export_my_pubkey_when_pubkey_not_set(monkeypatch):
|
||||
from bigchaindb import config
|
||||
from bigchaindb.commands.bigchaindb import run_export_my_pubkey
|
||||
|
||||
args = Namespace(config=None)
|
||||
monkeypatch.setitem(config['keypair'], 'public', None)
|
||||
# assert that run_export_my_pubkey(args) raises SystemExit:
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
run_export_my_pubkey(args)
|
||||
# exc_info is an object of class ExceptionInfo
|
||||
# https://pytest.org/latest/builtin.html#_pytest._code.ExceptionInfo
|
||||
assert exc_info.type == SystemExit
|
||||
# exc_info.value is an object of class SystemExit
|
||||
# https://docs.python.org/3/library/exceptions.html#SystemExit
|
||||
assert exc_info.value.code == \
|
||||
"This node's public key wasn't set anywhere so it can't be exported"
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
def test_bigchain_run_init_when_db_exists(mocker, capsys):
|
||||
from bigchaindb.commands.bigchaindb import run_init
|
||||
from bigchaindb.common.exceptions import DatabaseAlreadyExists
|
||||
@ -148,6 +85,7 @@ def test_bigchain_run_init_when_db_exists(mocker, capsys):
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
def test__run_init(mocker):
|
||||
from bigchaindb.commands.bigchaindb import _run_init
|
||||
bigchain_mock = mocker.patch(
|
||||
@ -164,6 +102,7 @@ def test__run_init(mocker):
|
||||
bigchain_mock.return_value.create_genesis_block.assert_called_once_with()
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
@patch('bigchaindb.backend.schema.drop_database')
|
||||
def test_drop_db_when_assumed_yes(mock_db_drop):
|
||||
from bigchaindb.commands.bigchaindb import run_drop
|
||||
@ -173,16 +112,19 @@ def test_drop_db_when_assumed_yes(mock_db_drop):
|
||||
assert mock_db_drop.called
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
@patch('bigchaindb.backend.schema.drop_database')
|
||||
def test_drop_db_when_interactive_yes(mock_db_drop, monkeypatch):
|
||||
from bigchaindb.commands.bigchaindb import run_drop
|
||||
args = Namespace(config=None, yes=False)
|
||||
monkeypatch.setattr('bigchaindb.commands.bigchaindb.input_on_stderr', lambda x: 'y')
|
||||
monkeypatch.setattr(
|
||||
'bigchaindb.commands.bigchaindb.input_on_stderr', lambda x: 'y')
|
||||
|
||||
run_drop(args)
|
||||
assert mock_db_drop.called
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
@patch('bigchaindb.backend.schema.drop_database')
|
||||
def test_drop_db_when_db_does_not_exist(mock_db_drop, capsys):
|
||||
from bigchaindb import config
|
||||
@ -197,27 +139,22 @@ def test_drop_db_when_db_does_not_exist(mock_db_drop, capsys):
|
||||
name=config['database']['name'])
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
@patch('bigchaindb.backend.schema.drop_database')
|
||||
def test_drop_db_does_not_drop_when_interactive_no(mock_db_drop, monkeypatch):
|
||||
from bigchaindb.commands.bigchaindb import run_drop
|
||||
args = Namespace(config=None, yes=False)
|
||||
monkeypatch.setattr('bigchaindb.commands.bigchaindb.input_on_stderr', lambda x: 'n')
|
||||
monkeypatch.setattr(
|
||||
'bigchaindb.commands.bigchaindb.input_on_stderr', lambda x: 'n')
|
||||
|
||||
run_drop(args)
|
||||
assert not mock_db_drop.called
|
||||
|
||||
|
||||
def test_run_configure_when_config_exists_and_skipping(monkeypatch):
|
||||
from bigchaindb.commands.bigchaindb import run_configure
|
||||
monkeypatch.setattr('os.path.exists', lambda path: True)
|
||||
args = Namespace(config='foo', yes=True)
|
||||
return_value = run_configure(args, skip_if_exists=True)
|
||||
assert return_value is None
|
||||
|
||||
|
||||
# TODO Beware if you are putting breakpoints in there, and using the '-s'
|
||||
# switch with pytest. It will just hang. Seems related to the monkeypatching of
|
||||
# input_on_stderr.
|
||||
@pytest.mark.tendermint
|
||||
def test_run_configure_when_config_does_not_exist(monkeypatch,
|
||||
mock_write_config,
|
||||
mock_generate_key_pair,
|
||||
@ -225,11 +162,12 @@ def test_run_configure_when_config_does_not_exist(monkeypatch,
|
||||
from bigchaindb.commands.bigchaindb import run_configure
|
||||
monkeypatch.setattr('os.path.exists', lambda path: False)
|
||||
monkeypatch.setattr('builtins.input', lambda: '\n')
|
||||
args = Namespace(config='foo', backend='rethinkdb', yes=True)
|
||||
args = Namespace(config=None, backend='localmongodb', yes=True)
|
||||
return_value = run_configure(args)
|
||||
assert return_value is None
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
def test_run_configure_when_config_does_exist(monkeypatch,
|
||||
mock_write_config,
|
||||
mock_generate_key_pair,
|
||||
@ -242,16 +180,17 @@ def test_run_configure_when_config_does_exist(monkeypatch,
|
||||
from bigchaindb.commands.bigchaindb import run_configure
|
||||
monkeypatch.setattr('os.path.exists', lambda path: True)
|
||||
monkeypatch.setattr('builtins.input', lambda: '\n')
|
||||
monkeypatch.setattr('bigchaindb.config_utils.write_config', mock_write_config)
|
||||
monkeypatch.setattr(
|
||||
'bigchaindb.config_utils.write_config', mock_write_config)
|
||||
|
||||
args = Namespace(config='foo', yes=None)
|
||||
args = Namespace(config=None, yes=None)
|
||||
run_configure(args)
|
||||
assert value == {}
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
@pytest.mark.parametrize('backend', (
|
||||
'rethinkdb',
|
||||
'mongodb',
|
||||
'localmongodb',
|
||||
))
|
||||
def test_run_configure_with_backend(backend, monkeypatch, mock_write_config):
|
||||
import bigchaindb
|
||||
@ -267,7 +206,7 @@ def test_run_configure_with_backend(backend, monkeypatch, mock_write_config):
|
||||
monkeypatch.setattr('bigchaindb.config_utils.write_config',
|
||||
mock_write_config)
|
||||
|
||||
args = Namespace(config='foo', backend=backend, yes=True)
|
||||
args = Namespace(config=None, backend=backend, yes=True)
|
||||
expected_config = bigchaindb.config
|
||||
run_configure(args)
|
||||
|
||||
@ -279,54 +218,6 @@ def test_run_configure_with_backend(backend, monkeypatch, mock_write_config):
|
||||
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')
|
||||
def test_allow_temp_keypair_generates_one_on_the_fly(
|
||||
mock_gen_keypair, mock_processes_start,
|
||||
mock_db_init_with_existing_db, mocked_setup_logging):
|
||||
import bigchaindb
|
||||
from bigchaindb.commands.bigchaindb import run_start
|
||||
|
||||
bigchaindb.config['keypair'] = {'private': None, 'public': None}
|
||||
|
||||
args = Namespace(allow_temp_keypair=True, start_rethinkdb=False, config=None, yes=True,
|
||||
skip_initialize_database=False)
|
||||
run_start(args)
|
||||
|
||||
mocked_setup_logging.assert_called_once_with(
|
||||
user_log_config=bigchaindb.config['log'])
|
||||
assert bigchaindb.config['keypair']['private'] == 'private_key'
|
||||
assert bigchaindb.config['keypair']['public'] == 'public_key'
|
||||
|
||||
|
||||
@patch('bigchaindb.common.crypto.generate_key_pair',
|
||||
return_value=('private_key', 'public_key'))
|
||||
@pytest.mark.usefixtures('ignore_local_config_file')
|
||||
def test_allow_temp_keypair_doesnt_override_if_keypair_found(mock_gen_keypair,
|
||||
mock_processes_start,
|
||||
mock_db_init_with_existing_db,
|
||||
mocked_setup_logging):
|
||||
import bigchaindb
|
||||
from bigchaindb.commands.bigchaindb import run_start
|
||||
|
||||
# Preconditions for the test
|
||||
original_private_key = bigchaindb.config['keypair']['private']
|
||||
original_public_key = bigchaindb.config['keypair']['public']
|
||||
|
||||
assert isinstance(original_public_key, str)
|
||||
assert isinstance(original_private_key, str)
|
||||
|
||||
args = Namespace(allow_temp_keypair=True, start_rethinkdb=False, config=None, yes=True,
|
||||
skip_initialize_database=False)
|
||||
run_start(args)
|
||||
|
||||
mocked_setup_logging.assert_called_once_with(
|
||||
user_log_config=bigchaindb.config['log'])
|
||||
assert bigchaindb.config['keypair']['private'] == original_private_key
|
||||
assert bigchaindb.config['keypair']['public'] == original_public_key
|
||||
|
||||
|
||||
def test_run_start_when_db_already_exists(mocker,
|
||||
monkeypatch,
|
||||
run_start_args,
|
||||
@ -338,7 +229,7 @@ def test_run_start_when_db_already_exists(mocker,
|
||||
|
||||
def mock_run_init():
|
||||
raise DatabaseAlreadyExists()
|
||||
|
||||
monkeypatch.setattr('builtins.input', lambda: '\x03')
|
||||
monkeypatch.setattr(
|
||||
'bigchaindb.commands.bigchaindb._run_init', mock_run_init)
|
||||
run_start(run_start_args)
|
||||
@ -346,58 +237,7 @@ def test_run_start_when_db_already_exists(mocker,
|
||||
assert mocked_start.called
|
||||
|
||||
|
||||
def test_run_start_when_keypair_not_found(mocker,
|
||||
monkeypatch,
|
||||
run_start_args,
|
||||
mocked_setup_logging):
|
||||
from bigchaindb import config
|
||||
from bigchaindb.commands.bigchaindb import run_start
|
||||
from bigchaindb.commands.messages import CANNOT_START_KEYPAIR_NOT_FOUND
|
||||
from bigchaindb.common.exceptions import KeypairNotFoundException
|
||||
mocked_start = mocker.patch('bigchaindb.processes.start')
|
||||
|
||||
def mock_run_init():
|
||||
raise KeypairNotFoundException()
|
||||
|
||||
monkeypatch.setattr(
|
||||
'bigchaindb.commands.bigchaindb._run_init', mock_run_init)
|
||||
|
||||
with pytest.raises(SystemExit) as exc:
|
||||
run_start(run_start_args)
|
||||
|
||||
mocked_setup_logging.assert_called_once_with(user_log_config=config['log'])
|
||||
assert len(exc.value.args) == 1
|
||||
assert exc.value.args[0] == CANNOT_START_KEYPAIR_NOT_FOUND
|
||||
assert not mocked_start.called
|
||||
|
||||
|
||||
def test_run_start_when_start_rethinkdb_fails(mocker,
|
||||
monkeypatch,
|
||||
run_start_args,
|
||||
mocked_setup_logging):
|
||||
from bigchaindb import config
|
||||
from bigchaindb.commands.bigchaindb import run_start
|
||||
from bigchaindb.commands.messages import RETHINKDB_STARTUP_ERROR
|
||||
from bigchaindb.common.exceptions import StartupError
|
||||
run_start_args.start_rethinkdb = True
|
||||
mocked_start = mocker.patch('bigchaindb.processes.start')
|
||||
err_msg = 'Error starting rethinkdb.'
|
||||
|
||||
def mock_start_rethinkdb():
|
||||
raise StartupError(err_msg)
|
||||
|
||||
monkeypatch.setattr(
|
||||
'bigchaindb.commands.utils.start_rethinkdb', mock_start_rethinkdb)
|
||||
|
||||
with pytest.raises(SystemExit) as exc:
|
||||
run_start(run_start_args)
|
||||
|
||||
mocked_setup_logging.assert_called_once_with(user_log_config=config['log'])
|
||||
assert len(exc.value.args) == 1
|
||||
assert exc.value.args[0] == RETHINKDB_STARTUP_ERROR.format(err_msg)
|
||||
assert not mocked_start.called
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
@patch('argparse.ArgumentParser.parse_args')
|
||||
@patch('bigchaindb.commands.utils.base_parser')
|
||||
@patch('bigchaindb.commands.utils.start')
|
||||
@ -419,107 +259,18 @@ def test_calling_main(start_mock, base_parser_mock, parse_args_mock,
|
||||
parser.add_subparsers.assert_called_with(title='Commands',
|
||||
dest='command')
|
||||
subparsers.add_parser.assert_any_call('configure',
|
||||
help='Prepare the config file '
|
||||
'and create the node keypair')
|
||||
help='Prepare the config file.')
|
||||
subparsers.add_parser.assert_any_call('show-config',
|
||||
help='Show the current '
|
||||
'configuration')
|
||||
subparsers.add_parserassert_any_call('export-my-pubkey',
|
||||
help="Export this node's public "
|
||||
'key')
|
||||
subparsers.add_parser.assert_any_call('init', help='Init the database')
|
||||
subparsers.add_parser.assert_any_call('drop', help='Drop the database')
|
||||
|
||||
subparsers.add_parser.assert_any_call('start', help='Start BigchainDB')
|
||||
subsubparsers.add_argument.assert_any_call('--dev-start-rethinkdb',
|
||||
dest='start_rethinkdb',
|
||||
action='store_true',
|
||||
help='Run RethinkDB on start')
|
||||
subsubparsers.add_argument.assert_any_call('--dev-allow-temp-keypair',
|
||||
dest='allow_temp_keypair',
|
||||
action='store_true',
|
||||
help='Generate a random keypair on start')
|
||||
|
||||
subparsers.add_parser.assert_any_call('set-shards',
|
||||
help='Configure number of shards')
|
||||
subsubparsers.add_argument.assert_any_call('num_shards',
|
||||
metavar='num_shards',
|
||||
type=int, default=1,
|
||||
help='Number of shards')
|
||||
|
||||
subparsers.add_parser.assert_any_call('set-replicas',
|
||||
help='Configure number of replicas')
|
||||
subsubparsers.add_argument.assert_any_call('num_replicas',
|
||||
metavar='num_replicas',
|
||||
type=int, default=1,
|
||||
help='Number of replicas (i.e. '
|
||||
'the replication factor)')
|
||||
|
||||
assert start_mock.called is True
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('ignore_local_config_file')
|
||||
@patch('bigchaindb.commands.bigchaindb.add_replicas')
|
||||
def test_run_add_replicas(mock_add_replicas):
|
||||
from bigchaindb.commands.bigchaindb import run_add_replicas
|
||||
from bigchaindb.backend.exceptions import OperationError
|
||||
|
||||
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
|
||||
assert mock_add_replicas.call_count == 1
|
||||
mock_add_replicas.reset_mock()
|
||||
|
||||
# test add_replicas with `OperationError`
|
||||
mock_add_replicas.side_effect = OperationError('err')
|
||||
with pytest.raises(SystemExit) as exc:
|
||||
run_add_replicas(args)
|
||||
assert exc.value.args == ('err',)
|
||||
assert mock_add_replicas.call_count == 1
|
||||
mock_add_replicas.reset_mock()
|
||||
|
||||
# test add_replicas with `NotImplementedError`
|
||||
mock_add_replicas.side_effect = NotImplementedError('err')
|
||||
with pytest.raises(SystemExit) as exc:
|
||||
run_add_replicas(args)
|
||||
assert exc.value.args == ('err',)
|
||||
assert mock_add_replicas.call_count == 1
|
||||
mock_add_replicas.reset_mock()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('ignore_local_config_file')
|
||||
@patch('bigchaindb.commands.bigchaindb.remove_replicas')
|
||||
def test_run_remove_replicas(mock_remove_replicas):
|
||||
from bigchaindb.commands.bigchaindb import run_remove_replicas
|
||||
from bigchaindb.backend.exceptions import OperationError
|
||||
|
||||
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
|
||||
assert mock_remove_replicas.call_count == 1
|
||||
mock_remove_replicas.reset_mock()
|
||||
|
||||
# test add_replicas with `OperationError`
|
||||
mock_remove_replicas.side_effect = OperationError('err')
|
||||
with pytest.raises(SystemExit) as exc:
|
||||
run_remove_replicas(args)
|
||||
assert exc.value.args == ('err',)
|
||||
assert mock_remove_replicas.call_count == 1
|
||||
mock_remove_replicas.reset_mock()
|
||||
|
||||
# test add_replicas with `NotImplementedError`
|
||||
mock_remove_replicas.side_effect = NotImplementedError('err')
|
||||
with pytest.raises(SystemExit) as exc:
|
||||
run_remove_replicas(args)
|
||||
assert exc.value.args == ('err',)
|
||||
assert mock_remove_replicas.call_count == 1
|
||||
mock_remove_replicas.reset_mock()
|
||||
|
||||
|
||||
@pytest.mark.tendermint
|
||||
@pytest.mark.bdb
|
||||
def test_recover_db_from_zombie_txn(b, monkeypatch):
|
||||
|
@ -1,5 +1,5 @@
|
||||
import argparse
|
||||
from argparse import ArgumentTypeError, Namespace
|
||||
from argparse import Namespace
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
@ -120,19 +120,3 @@ def test_start_sets_multiprocess_var_based_on_cli_args(mock_cpu_count):
|
||||
scope = {'run_mp_arg_test': run_mp_arg_test}
|
||||
assert utils.start(parser, ['mp_arg_test'], scope).multiprocess == 1
|
||||
assert utils.start(parser, ['mp_arg_test', '--multiprocess'], scope).multiprocess == 42
|
||||
|
||||
|
||||
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')
|
||||
|
||||
# bad host provided
|
||||
with pytest.raises(ArgumentTypeError):
|
||||
mongodb_host(':27017')
|
||||
|
Loading…
x
Reference in New Issue
Block a user