# 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 copy from unittest.mock import mock_open, patch import pytest import planetmint from planetmint.config import Config @pytest.fixture(scope='function', autouse=True) def clean_config(monkeypatch, request): original_config = Config().init_config('tarantool_db') backend = request.config.getoption('--database-backend') original_config['database'] = Config().get_db_map(backend) monkeypatch.setattr('planetmint.config', original_config) def test_bigchain_instance_is_initialized_when_conf_provided(): from planetmint import config_utils assert 'CONFIGURED' not in Config().get() config_utils.set_config({'database': {'backend': 'a'}}) assert Config().get()['CONFIGURED'] is True def test_load_validation_plugin_loads_default_rules_without_name(): from planetmint import config_utils from planetmint.validation import BaseValidationRules assert config_utils.load_validation_plugin() == BaseValidationRules def test_load_validation_plugin_raises_with_unknown_name(): from pkg_resources import ResolutionError from planetmint import config_utils with pytest.raises(ResolutionError): config_utils.load_validation_plugin('bogus') def test_load_validation_plugin_raises_with_invalid_subclass(monkeypatch): # Monkeypatch entry_point.load to return something other than a # ValidationRules instance from planetmint import config_utils import time monkeypatch.setattr(config_utils, 'iter_entry_points', lambda *args: [type('entry_point', (object, ), {'load': lambda: object})]) with pytest.raises(TypeError): # Since the function is decorated with `lru_cache`, we need to # "miss" the cache using a name that has not been used previously config_utils.load_validation_plugin(str(time.time())) def test_load_events_plugins(monkeypatch): from planetmint import config_utils monkeypatch.setattr(config_utils, 'iter_entry_points', lambda *args: [type('entry_point', (object, ), {'load': lambda: object})]) plugins = config_utils.load_events_plugins(['one', 'two']) assert len(plugins) == 2 def test_map_leafs_iterator(): from planetmint import config_utils mapping = { 'a': {'b': {'c': 1}, 'd': {'z': 44}}, 'b': {'d': 2}, 'c': 3 } result = config_utils.map_leafs(lambda x, path: x * 2, mapping) assert result == { 'a': {'b': {'c': 2}, 'd': {'z': 88}}, 'b': {'d': 4}, 'c': 6 } result = config_utils.map_leafs(lambda x, path: path, mapping) assert result == { 'a': {'b': {'c': ['a', 'b', 'c']}, 'd': {'z': ['a', 'd', 'z']}}, 'b': {'d': ['b', 'd']}, 'c': ['c'] } def test_update_types(): from planetmint import config_utils raw = { 'a_string': 'test', 'an_int': '42', 'a_float': '3.14', 'a_list': 'a:b:c', } reference = { 'a_string': 'test', 'an_int': 42, 'a_float': 3.14, 'a_list': ['a', 'b', 'c'], } result = config_utils.update_types(raw, reference) assert result == reference def test_env_config(monkeypatch): monkeypatch.setattr('os.environ', {'PLANETMINT_DATABASE_HOST': 'test-host', 'PLANETMINT_DATABASE_PORT': 'test-port'}) from planetmint import config_utils result = config_utils.env_config({'database': {'host': None, 'port': None}}) expected = {'database': {'host': 'test-host', 'port': 'test-port'}} assert result == expected def test_autoconfigure_read_both_from_file_and_env(monkeypatch, request): # TODO Disabled until we create a better config format return # constants # DATABASE_HOST = 'test-host' # DATABASE_NAME = 'test-dbname' # DATABASE_PORT = 4242 # DATABASE_BACKEND = request.config.getoption('--database-backend') # SERVER_BIND = '1.2.3.4:56' # WSSERVER_SCHEME = 'ws' # WSSERVER_HOST = '1.2.3.4' # WSSERVER_PORT = 57 # WSSERVER_ADVERTISED_SCHEME = 'wss' # WSSERVER_ADVERTISED_HOST = 'a.b.c.d' # WSSERVER_ADVERTISED_PORT = 89 # LOG_FILE = '/somewhere/something.log' # # file_config = { # 'database': { # 'host': DATABASE_HOST # }, # 'log': { # 'level_console': 'debug', # }, # } # # monkeypatch.setattr('planetmint.config_utils.file_config', # lambda *args, **kwargs: file_config) # # monkeypatch.setattr('os.environ', { # 'PLANETMINT_DATABASE_NAME': DATABASE_NAME, # 'PLANETMINT_DATABASE_PORT': str(DATABASE_PORT), # 'PLANETMINT_DATABASE_BACKEND': DATABASE_BACKEND, # 'PLANETMINT_SERVER_BIND': SERVER_BIND, # 'PLANETMINT_WSSERVER_SCHEME': WSSERVER_SCHEME, # 'PLANETMINT_WSSERVER_HOST': WSSERVER_HOST, # 'PLANETMINT_WSSERVER_PORT': WSSERVER_PORT, # 'PLANETMINT_WSSERVER_ADVERTISED_SCHEME': WSSERVER_ADVERTISED_SCHEME, # 'PLANETMINT_WSSERVER_ADVERTISED_HOST': WSSERVER_ADVERTISED_HOST, # 'PLANETMINT_WSSERVER_ADVERTISED_PORT': WSSERVER_ADVERTISED_PORT, # 'PLANETMINT_LOG_FILE': LOG_FILE, # 'PLANETMINT_LOG_FILE': LOG_FILE, # 'PLANETMINT_DATABASE_CA_CERT': 'ca_cert', # 'PLANETMINT_DATABASE_CRLFILE': 'crlfile', # 'PLANETMINT_DATABASE_CERTFILE': 'certfile', # 'PLANETMINT_DATABASE_KEYFILE': 'keyfile', # 'PLANETMINT_DATABASE_KEYFILE_PASSPHRASE': 'passphrase', # }) # # import planetmint # from planetmint import config_utils # from planetmint.log import DEFAULT_LOGGING_CONFIG as log_config # config_utils.autoconfigure() # # database_mongodb = { # 'backend': 'localmongodb', # 'host': DATABASE_HOST, # 'port': DATABASE_PORT, # 'name': DATABASE_NAME, # 'connection_timeout': 5000, # 'max_tries': 3, # 'replicaset': None, # 'ssl': False, # 'login': None, # 'password': None, # 'ca_cert': 'ca_cert', # 'certfile': 'certfile', # 'keyfile': 'keyfile', # 'keyfile_passphrase': 'passphrase', # 'crlfile': 'crlfile', # } # # assert planetmint.config == { # 'CONFIGURED': True, # 'server': { # 'bind': SERVER_BIND, # 'loglevel': 'info', # 'workers': None, # }, # 'wsserver': { # 'scheme': WSSERVER_SCHEME, # 'host': WSSERVER_HOST, # 'port': WSSERVER_PORT, # 'advertised_scheme': WSSERVER_ADVERTISED_SCHEME, # 'advertised_host': WSSERVER_ADVERTISED_HOST, # 'advertised_port': WSSERVER_ADVERTISED_PORT, # }, # 'database': database_mongodb, # 'tendermint': { # 'host': 'localhost', # 'port': 26657, # 'version': 'v0.31.5' # }, # 'log': { # 'file': LOG_FILE, # 'level_console': 'debug', # 'error_file': log_config['handlers']['errors']['filename'], # 'level_console': 'debug', # 'level_logfile': 'info', # 'datefmt_console': log_config['formatters']['console']['datefmt'], # 'datefmt_logfile': log_config['formatters']['file']['datefmt'], # 'fmt_console': log_config['formatters']['console']['format'], # 'fmt_logfile': log_config['formatters']['file']['format'], # 'granular_levels': {}, # }, # } def test_autoconfigure_env_precedence(monkeypatch): file_config = { 'database': {'host': 'test-host', 'name': 'planetmint', 'port': 28015} } monkeypatch.setattr('planetmint.config_utils.file_config', lambda *args, **kwargs: file_config) monkeypatch.setattr('os.environ', {'PLANETMINT_DATABASE_NAME': 'test-dbname', 'PLANETMINT_DATABASE_PORT': 4242, 'PLANETMINT_SERVER_BIND': 'localhost:9985'}) from planetmint import config_utils from planetmint.config import Config config_utils.autoconfigure() assert Config().get()['CONFIGURED'] assert Config().get()['database']['host'] == 'test-host' assert Config().get()['database']['name'] == 'test-dbname' assert Config().get()['database']['port'] == 4242 assert Config().get()['server']['bind'] == 'localhost:9985' def test_autoconfigure_explicit_file(monkeypatch): from planetmint import config_utils def file_config(*args, **kwargs): raise FileNotFoundError() monkeypatch.setattr('planetmint.config_utils.file_config', file_config) with pytest.raises(FileNotFoundError): config_utils.autoconfigure(filename='autoexec.bat') def test_update_config(monkeypatch): import planetmint from planetmint import config_utils file_config = { 'database': {'host': 'test-host', 'name': 'planetmint', 'port': 28015} } monkeypatch.setattr('planetmint.config_utils.file_config', lambda *args, **kwargs: file_config) config_utils.autoconfigure(config=file_config) # update configuration, retaining previous changes config_utils.update_config({'database': {'port': 28016, 'name': 'planetmint_other'}}) assert Config().get()['database']['host'] == 'test-host' assert Config().get()['database']['name'] == 'planetmint_other' assert Config().get()['database']['port'] == 28016 def test_file_config(): from planetmint.config_utils import file_config, CONFIG_DEFAULT_PATH with patch('builtins.open', mock_open(read_data='{}')) as m: config = file_config() m.assert_called_once_with(CONFIG_DEFAULT_PATH) assert config == {} def test_invalid_file_config(): from planetmint.config_utils import file_config from planetmint.common import exceptions with patch('builtins.open', mock_open(read_data='{_INVALID_JSON_}')): with pytest.raises(exceptions.ConfigurationError): file_config() def test_write_config(): from planetmint.config_utils import write_config, CONFIG_DEFAULT_PATH m = mock_open() with patch('builtins.open', m): write_config({}) m.assert_called_once_with(CONFIG_DEFAULT_PATH, 'w') handle = m() handle.write.assert_called_once_with('{}') @pytest.mark.parametrize('env_name,env_value,config_key', ( ('PLANETMINT_DATABASE_BACKEND', 'test-backend', 'backend'), ('PLANETMINT_DATABASE_HOST', 'test-host', 'host'), ('PLANETMINT_DATABASE_PORT', 4242, 'port'), ('PLANETMINT_DATABASE_NAME', 'test-db', 'name'), )) def test_database_envs(env_name, env_value, config_key, monkeypatch): import planetmint monkeypatch.setattr('os.environ', {env_name: env_value}) planetmint.config_utils.autoconfigure() expected_config = Config().get() expected_config['database'][config_key] = env_value assert planetmint.config == expected_config