new structure of connections

This commit is contained in:
andrei 2022-03-09 17:35:05 +02:00
parent 3ab1922dba
commit 7e5e4c3102
11 changed files with 253 additions and 344 deletions

View File

@ -14,4 +14,4 @@ configuration or the ``PLANETMINT_DATABASE_BACKEND`` environment variable.
# Include the backend interfaces
from planetmint.backend import schema, query # noqa
from planetmint.backend.connection_tarantool import connect # noqa
from planetmint.backend.connection import Connection

View File

@ -3,168 +3,29 @@
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0
import sys
import logging
from importlib import import_module
from itertools import repeat
import planetmint
from planetmint.backend.exceptions import ConnectionError
from planetmint.backend.utils import get_planetmint_config_value, get_planetmint_config_value_or_key_error
from planetmint.common.exceptions import ConfigurationError
BACKENDS = { # This is path to MongoDBClass
'localmongodb': 'planetmint.backend.localmongodb.connection.LocalMongoDBConnection',
'tarantool_db': 'planetmint.backend.tarantool.connection.TarantoolDB',
'localmongodb': 'planetmint.backend.localmongodb.connection.LocalMongoDBConnection'
}
logger = logging.getLogger(__name__)
def connect(backend=None, host=None, port=None, name=None, max_tries=None,
connection_timeout=None, replicaset=None, ssl=None, login=None, password=None,
ca_cert=None, certfile=None, keyfile=None, keyfile_passphrase=None,
crlfile=None):
"""Create a new connection to the database backend.
All arguments default to the current configuration's values if not
given.
Args:
backend (str): the name of the backend to use.
host (str): the host to connect to.
port (int): the port to connect to.
name (str): the name of the database to use.
replicaset (str): the name of the replica set (only relevant for
MongoDB connections).
Returns:
An instance of :class:`~planetmint.backend.connection.Connection`
based on the given (or defaulted) :attr:`backend`.
Raises:
:exc:`~ConnectionError`: If the connection to the database fails.
:exc:`~ConfigurationError`: If the given (or defaulted) :attr:`backend`
is not supported or could not be loaded.
:exc:`~AuthenticationError`: If there is a OperationFailure due to
Authentication failure after connecting to the database.
"""
backend = backend or get_planetmint_config_value_or_key_error('backend')
host = host or get_planetmint_config_value_or_key_error('host')
port = port or get_planetmint_config_value_or_key_error('port')
dbname = name or get_planetmint_config_value_or_key_error('name')
# Not sure how to handle this here. This setting is only relevant for
# mongodb.
# I added **kwargs for both RethinkDBConnection and MongoDBConnection
# to handle these these additional args. In case of RethinkDBConnection
# it just does not do anything with it.
#
# UPD: RethinkDBConnection is not here anymore cause we no longer support RethinkDB.
# The problem described above might be reconsidered next time we introduce a backend,
# if it ever happens.
replicaset = replicaset or get_planetmint_config_value('replicaset')
ssl = ssl if ssl is not None else get_planetmint_config_value('ssl', False)
login = login or get_planetmint_config_value('login')
password = password or get_planetmint_config_value('password')
ca_cert = ca_cert or get_planetmint_config_value('ca_cert')
certfile = certfile or get_planetmint_config_value('certfile')
keyfile = keyfile or get_planetmint_config_value('keyfile')
keyfile_passphrase = keyfile_passphrase or get_planetmint_config_value('keyfile_passphrase', None)
crlfile = crlfile or get_planetmint_config_value('crlfile')
try: # Here we get class using getattr function
module_name, _, class_name = BACKENDS[backend].rpartition('.')
Class = getattr(import_module(module_name), class_name)
except KeyError:
raise ConfigurationError('Backend `{}` is not supported. '
'Planetmint currently supports {}'.format(backend, BACKENDS.keys()))
except (ImportError, AttributeError) as exc:
raise ConfigurationError('Error loading backend `{}`'.format(backend)) from exc
logger.debug('Connection: {}'.format(Class))
return Class(host=host, port=port, dbname=dbname,
max_tries=max_tries, connection_timeout=connection_timeout,
replicaset=replicaset, ssl=ssl, login=login, password=password,
ca_cert=ca_cert, certfile=certfile, keyfile=keyfile,
keyfile_passphrase=keyfile_passphrase, crlfile=crlfile)
modulename = sys.modules[__name__]
backend = get_planetmint_config_value("backend")
current_backend = getattr(modulename, BACKENDS[backend])
class Connection:
"""Connection class interface.
class Connection(current_backend):
pass
All backend implementations should provide a connection class that inherits
from and implements this class.
"""
def __init__(self, host=None, port=None, dbname=None,
connection_timeout=None, max_tries=None,
**kwargs):
"""Create a new :class:`~.Connection` instance.
Args:
host (str): the host to connect to.
port (int): the port to connect to.
dbname (str): the name of the database to use.
connection_timeout (int, optional): the milliseconds to wait
until timing out the database connection attempt.
Defaults to 5000ms.
max_tries (int, optional): how many tries before giving up,
if 0 then try forever. Defaults to 3.
**kwargs: arbitrary keyword arguments provided by the
configuration's ``database`` settings
"""
dbconf = planetmint.config['database']
self.host = host or dbconf['host']
self.port = port or dbconf['port']
self.dbname = dbname or dbconf['name']
self.connection_timeout = connection_timeout if connection_timeout is not None \
else dbconf['connection_timeout']
self.max_tries = max_tries if max_tries is not None else dbconf['max_tries']
self.max_tries_counter = range(self.max_tries) if self.max_tries != 0 else repeat(0)
self._conn = None
@property
def conn(self):
if self._conn is None:
self.connect()
return self._conn
def run(self, query):
"""Run a query.
Args:
query: the query to run
Raises:
:exc:`~DuplicateKeyError`: If the query fails because of a
duplicate key constraint.
:exc:`~OperationFailure`: If the query fails for any other
reason.
:exc:`~ConnectionError`: If the connection to the database
fails.
"""
raise NotImplementedError()
def connect(self):
"""Try to connect to the database.
Raises:
:exc:`~ConnectionError`: If the connection to the database
fails.
"""
attempt = 0
for i in self.max_tries_counter:
attempt += 1
try:
self._conn = self._connect()
except ConnectionError as exc:
logger.warning('Attempt %s/%s. Connection to %s:%s failed after %sms.',
attempt, self.max_tries if self.max_tries != 0 else '',
self.host, self.port, self.connection_timeout)
if attempt == self.max_tries:
logger.critical('Cannot connect to the Database. Giving up.')
raise ConnectionError() from exc
else:
break

View File

@ -1,160 +0,0 @@
# Copyright © 2020 Interplanetary Database Association e.V.,
# Planetmint and IPDB software contributors.
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0
import logging
from importlib import import_module
from itertools import repeat
import tarantool
import planetmint
from planetmint.backend.exceptions import ConnectionError
from planetmint.backend.utils import get_planetmint_config_value, get_planetmint_config_value_or_key_error
from planetmint.common.exceptions import ConfigurationError
BACKENDS = { # This is path to MongoDBClass
'tarantool_db': 'planetmint.backend.connection_tarantool.TarantoolDB',
}
logger = logging.getLogger(__name__)
class TarantoolDB:
def __init__(self, host: str, port: int, user: str, password: str, reset_database: bool = False):
self.db_connect = tarantool.connect(host=host, port=port, user=user, password=password)
if reset_database:
self.drop_database()
self.init_database()
def get_connection(self, space_name: str = None):
return self.db_connect if space_name is None else self.db_connect.space(space_name)
def __read_commands(self, file_path):
with open(file_path, "r") as cmd_file:
commands = [line.strip() for line in cmd_file.readlines() if len(str(line)) > 1]
cmd_file.close()
return commands
def drop_database(self):
from planetmint.backend.tarantool.utils import run
config = get_planetmint_config_value_or_key_error("ctl_config")
drop_config = config["drop_config"]
f_path = "%s%s" % (drop_config["relative_path"], drop_config["drop_file"])
commands = self.__read_commands(file_path=f_path)
run(commands=commands, config=config)
def init_database(self):
from planetmint.backend.tarantool.utils import run
config = get_planetmint_config_value_or_key_error("ctl_config")
init_config = config["init_config"]
f_path = "%s%s" % (init_config["relative_path"], init_config["init_file"])
commands = self.__read_commands(file_path=f_path)
run(commands=commands, config=config)
def connect(host: str = None, port: int = None, username: str = "admin", password: str = "pass",
backend: str = None, reset_database: bool = False, name=None, max_tries=None,
connection_timeout=None, replicaset=None, ssl=None, login: str = "admin", ctl_config=None,
ca_cert=None, certfile=None, keyfile=None, keyfile_passphrase=None, reconnect_delay=None,
crlfile=None, connect_now=True, encoding=None):
backend = backend or get_planetmint_config_value_or_key_error('backend') # TODO Rewrite Configs
host = host or get_planetmint_config_value_or_key_error('host')
port = port or get_planetmint_config_value_or_key_error('port')
username = username or login or get_planetmint_config_value('login')
password = password or get_planetmint_config_value('password')
try: # Here we get class using getattr function
module_name, _, class_name = BACKENDS[backend].rpartition('.')
Class = getattr(import_module(module_name), class_name)
except KeyError:
raise ConfigurationError('Backend `{}` is not supported. '
'Planetmint currently supports {}'.format(backend, BACKENDS.keys()))
except (ImportError, AttributeError) as exc:
raise ConfigurationError('Error loading backend `{}`'.format(backend)) from exc
logger.debug('Connection: {}'.format(Class))
return Class(host=host, port=port, user=username, password=password, reset_database=reset_database)
class Connection:
"""Connection class interface.
All backend implementations should provide a connection class that inherits
from and implements this class.
"""
def __init__(self, host=None, port=None, connection_timeout=None, max_tries=None,
**kwargs):
"""Create a new :class:`~.Connection` instance.
Args:
host (str): the host to connect to.
port (int): the port to connect to.
dbname (str): the name of the database to use.
connection_timeout (int, optional): the milliseconds to wait
until timing out the database connection attempt.
Defaults to 5000ms.
max_tries (int, optional): how many tries before giving up,
if 0 then try forever. Defaults to 3.
**kwargs: arbitrary keyword arguments provided by the
configuration's ``database`` settings
"""
dbconf = planetmint.config['database']
self.host = host or dbconf['host']
self.port = port or dbconf['port']
self.connection_timeout = connection_timeout if connection_timeout is not None \
else dbconf['connection_timeout']
self.max_tries = max_tries if max_tries is not None else dbconf['max_tries']
self.max_tries_counter = range(self.max_tries) if self.max_tries != 0 else repeat(0)
self._conn = None
@property
def conn(self):
pass
if self._conn is None:
self.connect()
return self._conn
def run(self, query):
pass
"""Run a query.
Args:
query: the query to run
Raises:
:exc:`~DuplicateKeyError`: If the query fails because of a
duplicate key constraint.
:exc:`~OperationFailure`: If the query fails for any other
reason.
:exc:`~ConnectionError`: If the connection to the database
fails.
"""
raise NotImplementedError()
def connect(self):
pass
"""Try to connect to the database.
Raises:
:exc:`~ConnectionError`: If the connection to the database
fails.
"""
attempt = 0
for i in self.max_tries_counter:
attempt += 1
try:
self._conn = self._connect()
except ConnectionError as exc:
logger.warning('Attempt %s/%s. Connection to %s:%s failed after %sms.',
attempt, self.max_tries if self.max_tries != 0 else '',
self.host, self.port, self.connection_timeout)
if attempt == self.max_tries:
logger.critical('Cannot connect to the Database. Giving up.')
raise ConnectionError() from exc
else:
break

View File

@ -4,11 +4,11 @@
# Code is Apache-2.0 and docs are CC-BY-4.0
import logging
import bigchaindb
from ssl import CERT_REQUIRED
import pymongo
from planetmint.backend.connection import Connection
from planetmint.backend.exceptions import (DuplicateKeyError,
OperationError,
ConnectionError)
@ -19,6 +19,84 @@ from planetmint.utils import Lazy
logger = logging.getLogger(__name__)
class Connection:
"""Connection class interface.
All backend implementations should provide a connection class that inherits
from and implements this class.
"""
def __init__(self, host=None, port=None, dbname=None,
connection_timeout=None, max_tries=None,
**kwargs):
"""Create a new :class:`~.Connection` instance.
Args:
host (str): the host to connect to.
port (int): the port to connect to.
dbname (str): the name of the database to use.
connection_timeout (int, optional): the milliseconds to wait
until timing out the database connection attempt.
Defaults to 5000ms.
max_tries (int, optional): how many tries before giving up,
if 0 then try forever. Defaults to 3.
**kwargs: arbitrary keyword arguments provided by the
configuration's ``database`` settings
"""
dbconf = bigchaindb.config['database']
self.host = host or dbconf['host']
self.port = port or dbconf['port']
self.dbname = dbname or dbconf['name']
self.connection_timeout = connection_timeout if connection_timeout is not None \
else dbconf['connection_timeout']
self.max_tries = max_tries if max_tries is not None else dbconf['max_tries']
self.max_tries_counter = range(self.max_tries) if self.max_tries != 0 else repeat(0)
self._conn = None
@property
def conn(self):
if self._conn is None:
self.connect()
return self._conn
def run(self, query):
"""Run a query.
Args:
query: the query to run
Raises:
:exc:`~DuplicateKeyError`: If the query fails because of a
duplicate key constraint.
:exc:`~OperationFailure`: If the query fails for any other
reason.
:exc:`~ConnectionError`: If the connection to the database
fails.
"""
raise NotImplementedError()
def connect(self):
"""Try to connect to the database.
Raises:
:exc:`~ConnectionError`: If the connection to the database
fails.
"""
attempt = 0
for i in self.max_tries_counter:
attempt += 1
try:
self._conn = self._connect()
except ConnectionError as exc:
logger.warning('Attempt %s/%s. Connection to %s:%s failed after %sms.',
attempt, self.max_tries if self.max_tries != 0 else '',
self.host, self.port, self.connection_timeout)
if attempt == self.max_tries:
logger.critical('Cannot connect to the Database. Giving up.')
raise ConnectionError() from exc
else:
break
class LocalMongoDBConnection(Connection):
def __init__(self, replicaset=None, ssl=None, login=None, password=None,

View File

@ -9,8 +9,7 @@ from functools import singledispatch
import logging
import planetmint
from planetmint.backend.connection import connect as connect_mongo
from planetmint.backend.connection_tarantool import connect
from planetmint.backend.connection import Connection
from planetmint.common.exceptions import ValidationError
from planetmint.common.utils import validate_all_values_for_key_in_obj, validate_all_values_for_key_in_list
@ -64,7 +63,7 @@ def drop_database(connection, dbname):
raise NotImplementedError
def init_database(connection=None, dbname=None):
def init_database(connection=None, dbname=None): # FIXME HERE IS INIT DATABASE
"""Initialize the configured backend for use with Planetmint.
Creates a database with :attr:`dbname` with any required tables
@ -79,7 +78,7 @@ def init_database(connection=None, dbname=None):
configuration.
"""
connection = connection or connect()
connection = connection or Connection()
dbname = dbname or planetmint.config['database']['name']
create_database(connection, dbname)

View File

View File

@ -0,0 +1,55 @@
# Copyright © 2020 Interplanetary Database Association e.V.,
# Planetmint and IPDB software contributors.
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0
import logging
from importlib import import_module
from itertools import repeat
import tarantool
import planetmint
from planetmint.backend.exceptions import ConnectionError
from planetmint.backend.utils import get_planetmint_config_value, get_planetmint_config_value_or_key_error
from planetmint.common.exceptions import ConfigurationError
BACKENDS = { # This is path to MongoDBClass
'tarantool_db': 'planetmint.backend.connection_tarantool.TarantoolDB',
'localmongodb': 'planetmint.backend.localmongodb.connection.LocalMongoDBConnection'
}
logger = logging.getLogger(__name__)
class TarantoolDB:
def __init__(self, host: str, port: int, user: str, password: str, reset_database: bool = False):
self.db_connect = tarantool.connect(host=host, port=port, user=user, password=password)
if reset_database:
self.drop_database()
self.init_database()
def get_connection(self, space_name: str = None):
return self.db_connect if space_name is None else self.db_connect.space(space_name)
def __read_commands(self, file_path):
with open(file_path, "r") as cmd_file:
commands = [line.strip() for line in cmd_file.readlines() if len(str(line)) > 1]
cmd_file.close()
return commands
def drop_database(self):
from planetmint.backend.tarantool.utils import run
config = get_planetmint_config_value_or_key_error("ctl_config")
drop_config = config["drop_config"]
f_path = "%s%s" % (drop_config["relative_path"], drop_config["drop_file"])
commands = self.__read_commands(file_path=f_path)
run(commands=commands, config=config)
def init_database(self):
from planetmint.backend.tarantool.utils import run
config = get_planetmint_config_value_or_key_error("ctl_config")
init_config = config["init_config"]
f_path = "%s%s" % (init_config["relative_path"], init_config["init_file"])
commands = self.__read_commands(file_path=f_path)
run(commands=commands, config=config)

View File

@ -76,7 +76,7 @@ class Planetmint(object):
else:
self.validation = BaseValidationRules
self.connection = connection if connection else backend.connection_tarantool.connect(**planetmint.config['database'])
self.connection = connection if connection else planetmint.backend.tarantool.connection_tarantool.connect(**planetmint.config['database'])
def post_transaction(self, transaction, mode):
"""Submit a valid transaction to the mempool."""

View File

@ -180,7 +180,7 @@ def test_write_metadata():
# check that 3 assets were written to the database
cursor = conn.db.metadata.find({}, projection={'_id': False})\
.sort('id', pymongo.ASCENDING)
TarantoolDB
assert cursor.collection.count_documents({}) == 3
assert list(cursor) == metadata

View File

@ -9,16 +9,16 @@ import pytest
# import pymongo
# from planetmint.backend import connect, query
# from planetmint.backend.connection import Connection, query
pytestmark = pytest.mark.bdb
def test_get_txids_filtered(signed_create_tx, signed_transfer_tx):
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
from planetmint.models import Transaction
conn = connect(reset_database=True).get_connection()
conn = Connection(reset_database=True).get_connection()
# create and insert two blocks, one for the create and one for the
# transfer transaction
create_tx_dict = signed_create_tx.to_dict()
@ -43,9 +43,9 @@ def test_get_txids_filtered(signed_create_tx, signed_transfer_tx):
def test_write_assets():
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
conn = connect().get_connection()
conn = Connection().get_connection()
assets = [
{'id': "1", 'data': '1'},
{'id': "2", 'data': '2'},
@ -66,9 +66,9 @@ def test_write_assets():
def test_get_assets():
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
conn = connect().get_connection()
conn = Connection().get_connection()
assets = [
{'id': "1", 'data': '1'},
@ -167,9 +167,9 @@ def test_text_search(table):
def test_write_metadata():
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
conn = connect().get_connection()
conn = Connection().get_connection()
metadata = [
{'id': "1", 'data': '1'},
@ -194,9 +194,9 @@ def test_write_metadata():
def test_get_metadata():
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
conn = connect().get_connection()
conn = Connection().get_connection()
metadata = [
{'id': "dd86682db39e4b424df0eec1413cfad65488fd48712097c5d865ca8e8e059b64", 'metadata': None},
@ -211,9 +211,9 @@ def test_get_metadata():
def test_get_owned_ids(signed_create_tx, user_pk):
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
conn = connect().get_connection()
conn = Connection().get_connection()
# insert a transaction
query.store_transactions(connection=conn, signed_transactions=[signed_create_tx.to_dict()])
@ -225,9 +225,9 @@ def test_get_owned_ids(signed_create_tx, user_pk):
def test_get_spending_transactions(user_pk, user_sk):
from planetmint.models import Transaction
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
conn = connect().get_connection()
conn = Connection().get_connection()
out = [([user_pk], 1)]
tx1 = Transaction.create([user_pk], out * 3)
@ -249,10 +249,10 @@ def test_get_spending_transactions(user_pk, user_sk):
def test_get_spending_transactions_multiple_inputs():
from planetmint.models import Transaction
from planetmint.common.crypto import generate_key_pair
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
conn = connect().get_connection()
conn = Connection().get_connection()
(alice_sk, alice_pk) = generate_key_pair()
(bob_sk, bob_pk) = generate_key_pair()
@ -294,10 +294,10 @@ def test_get_spending_transactions_multiple_inputs():
def test_store_block():
from planetmint.lib import Block
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
conn = connect().get_connection()
conn = Connection().get_connection()
block = Block(app_hash='random_utxo',
height=3,
@ -310,10 +310,10 @@ def test_store_block():
def test_get_block():
from planetmint.lib import Block
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
conn = connect().get_connection()
conn = Connection().get_connection()
block = Block(app_hash='random_utxo',
height=3,
@ -424,10 +424,10 @@ def test_get_block():
def test_store_pre_commit_state(db_context):
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
conn = connect().get_connection()
conn = Connection().get_connection()
state = dict(height=3, transactions=[])
@ -440,10 +440,10 @@ def test_store_pre_commit_state(db_context):
def test_get_pre_commit_state(db_context):
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
conn = connect().get_connection()
conn = Connection().get_connection()
space = conn.space("pre_commits")
all_pre = space.select([])
for pre in all_pre.data:
@ -457,10 +457,10 @@ def test_get_pre_commit_state(db_context):
def test_validator_update():
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
conn = connect().get_connection()
conn = Connection().get_connection()
def gen_validator_update(height):
return {'validators': [], 'height': height, 'election_id': f'election_id_at_height_{height}'}
@ -519,10 +519,10 @@ def test_validator_update():
),
])
def test_store_abci_chain(description, stores, expected):
from planetmint.backend import connect
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool import query
conn = connect().get_connection()
conn = Connection().get_connection()
for store in stores:
query.store_abci_chain(conn, **store)

View File

@ -0,0 +1,76 @@
# Copyright © 2020 Interplanetary Database Association e.V.,
# Planetmint and IPDB software contributors.
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0
def test_init_database_is_graceful_if_db_exists():
import planetmint
from planetmint import backend
from planetmint.backend.schema import init_database
conn = backend.connect()
dbname = planetmint.config['database']['name']
# The db is set up by the fixtures
assert dbname in conn.conn.list_database_names()
init_database()
def test_create_tables():
import planetmint
from planetmint import backend
from planetmint.backend import schema
conn = backend.connect()
dbname = planetmint.config['database']['name']
# The db is set up by the fixtures so we need to remove it
conn.conn.drop_database(dbname)
schema.create_database(conn, dbname)
schema.create_tables(conn, dbname)
collection_names = conn.conn[dbname].list_collection_names()
assert set(collection_names) == {
'transactions', 'assets', 'metadata', 'blocks', 'utxos', 'validators', 'elections',
'pre_commit', 'abci_chains',
}
indexes = conn.conn[dbname]['assets'].index_information().keys()
assert set(indexes) == {'_id_', 'asset_id', 'text'}
index_info = conn.conn[dbname]['transactions'].index_information()
indexes = index_info.keys()
assert set(indexes) == {
'_id_', 'transaction_id', 'asset_id', 'outputs', 'inputs'}
assert index_info['transaction_id']['unique']
index_info = conn.conn[dbname]['blocks'].index_information()
indexes = index_info.keys()
assert set(indexes) == {'_id_', 'height'}
assert index_info['height']['unique']
index_info = conn.conn[dbname]['utxos'].index_information()
assert set(index_info.keys()) == {'_id_', 'utxo'}
assert index_info['utxo']['unique']
assert index_info['utxo']['key'] == [('transaction_id', 1),
('output_index', 1)]
indexes = conn.conn[dbname]['elections'].index_information()
assert set(indexes.keys()) == {'_id_', 'election_id_height'}
assert indexes['election_id_height']['unique']
indexes = conn.conn[dbname]['pre_commit'].index_information()
assert set(indexes.keys()) == {'_id_', 'height'}
assert indexes['height']['unique']
def test_drop(dummy_db):
from planetmint import backend
from planetmint.backend import schema
conn = backend.connect()
assert dummy_db in conn.conn.list_database_names()
schema.drop_database(conn, dummy_db)
assert dummy_db not in conn.conn.list_database_names()