from ast import literal_eval
from pyramid.config import Configurator
import logging
-import pkg_resources
import sys
+from pgwui_common import plugin
+
# Constants
# All the settings recognized by PGWUI
# Functions
-def abort_on_bad_setting(errors, key):
+def abort_on_bad_setting(errors, key, component_keys):
'''Abort on a bad pgwui setting
'''
if key[:6] == 'pgwui.':
- if key[6:] not in SETTINGS:
+ if (key[6:] not in SETTINGS
+ and key not in component_keys):
errors.append(UnknownSettingKeyError(key))
errors.append(BadLiteralColumnHeadingsError(value))
-def validate_settings(errors, settings):
+def validate_settings(errors, settings, components):
'''Be sure all settings validate
'''
+ component_keys = ['pgwui.{}'.format(component) for component in components]
for key in settings.keys():
- abort_on_bad_setting(errors, key)
+ abort_on_bad_setting(errors, component_keys, key)
validate_setting_values(errors, settings)
validate_hmac(errors, settings)
sys.exit(1)
-def exit_on_invalid_settings(settings):
+def exit_on_invalid_settings(settings, components):
'''Exit when settings don't validate
'''
errors = []
- validate_settings(errors, settings)
+ validate_settings(errors, settings, components)
if errors:
exit_reporting_errors(errors)
config.add_route(name, route)
-def find_pgwui_components():
- '''Return list of all pgwui component names as strings
- '''
- return [entry_point.resolve().__name__ for entry_point in
- pkg_resources.iter_entry_points('pgwui.components')]
-
-
-def autoconfig_components(settings):
+def autoconfigurable_components(settings, components):
'''Automatic pgwui component discovery
'''
autoconfig = settings.get('pgwui.autoconfigure')
if 'pyramid.include' in settings:
log.info(AutoconfigureConflict())
- return find_pgwui_components()
+ return components
-def pgwui_server_config(settings):
- '''Configure pyramid
+def apply_component_defaults(settings, components):
+ '''Apply component default settings to existing settings
'''
- exit_on_invalid_settings(settings)
-
- components = autoconfig_components(settings)
+ components_to_config = autoconfigurable_components(settings, components)
rp = settings.get('pgwui.route_prefix')
with Configurator(settings=settings, route_prefix=rp) as config:
config.include('pgwui_common')
- for component in components:
+ for component in components_to_config:
config.include(component)
add_routes(config, settings)
return config
+def pgwui_server_config(settings):
+ '''Configure pyramid
+ '''
+ components = plugin.find_pgwui_components()
+ exit_on_invalid_settings(settings, components)
+ return apply_component_defaults(settings, components)
+
+
def main(global_config, **settings):
'''Return a Pyramid WSGI application
'''
-# Copyright (C) 2018, 2019 The Meme Factory, Inc. http://www.meme.com/
+# Copyright (C) 2018, 2019, 2020 The Meme Factory, Inc.
+# http://www.karlpinc.com/
# This file is part of PGWUI_Server.
#
# <http://www.gnu.org/licenses/>.
#
-# Karl O. Pinc <kop@meme.com>
+# Karl O. Pinc <kop@karlpinc.com>
import logging
import pytest
import sys
+import pyramid.testing
+
+import pgwui_common.plugin
+# Use as a regular module, not a plugin, so lint checks work
+from pgwui_testing import testing
+
import pgwui_server.__init__ as pgwui_server_init
# Use contextlib.AbstractContextManager for Python >= 3.6
+# (Or, better, use the magic mock maker that's not yet integrated.)
class MockConfigurator():
def __init__(self, **kwargs):
pass
pass
-class MockConfig():
- def __init__(self):
- self.add_route_called = 0
+mock_add_route = testing.instance_method_mock_fixture('add_route')
- def add_route(self, *args):
- self.add_route_called += 1
+mock_find_pgwui_components = testing.make_mock_fixture(
+ pgwui_common.plugin, 'find_pgwui_components')
# Unit tests
def test_abort_on_bad_setting_unknown():
'''Nothing bad happens when there's a non-pgwui setting'''
errors = []
- pgwui_server_init.abort_on_bad_setting(errors, 'foo')
+ pgwui_server_init.abort_on_bad_setting(errors, 'foo', [])
assert errors == []
def test_abort_on_bad_setting_bad():
'''Delivers an error on a bad pgwui setting'''
errors = []
- pgwui_server_init.abort_on_bad_setting(errors, 'pgwui.foo')
+ pgwui_server_init.abort_on_bad_setting(errors, 'pgwui.foo', [])
assert errors
assert isinstance(errors[0], pgwui_server_init.UnknownSettingKeyError)
def test_abort_on_bad_setting_good():
'''Does nothing when a known pgwui setting is supplied'''
errors = []
- pgwui_server_init.abort_on_bad_setting(errors, 'pgwui.pg_host')
+ pgwui_server_init.abort_on_bad_setting(errors, 'pgwui.pg_host', [])
+
+ assert errors == []
+
+
+def test_abort_on_bad_setting_plugin():
+ '''Does nothing when a known plugin has a setting'''
+ errors = []
+ pgwui_server_init.abort_on_bad_setting(
+ errors, 'pgwui.pgwui_upload', ['pgwui.pgwui_upload'])
assert errors == []
+mock_abort_on_bad_setting = testing.make_mock_fixture(
+ pgwui_server_init, 'abort_on_bad_setting')
+
+
# require_setting()
def test_require_setting_missing():
assert errors == []
+mock_require_setting = testing.make_mock_fixture(
+ pgwui_server_init, 'require_setting')
+
+
# boolean_setting()
def test_boolean_setting_missing():
assert isinstance(errors[0], pgwui_server_init.NotBooleanSettingError)
+mock_boolean_setting = testing.make_mock_fixture(
+ pgwui_server_init, 'boolean_setting')
+
+
# validate_setting_values()
-def test_validate_setting_values(monkeypatch):
+def test_validate_setting_values(mock_require_setting, mock_boolean_setting):
'''Calls require_setting() and boolean_setting()'''
- require_setting_called = False
- boolean_setting_called = False
-
- def mock_require_setting(*args):
- nonlocal require_setting_called
- require_setting_called = True
- def mock_boolean_setting(*args):
- nonlocal boolean_setting_called
- boolean_setting_called = True
+ pgwui_server_init.validate_setting_values([], {})
- monkeypatch.setattr(pgwui_server_init, 'require_setting',
- mock_require_setting)
- monkeypatch.setattr(pgwui_server_init, 'boolean_setting',
- mock_boolean_setting)
+ assert mock_require_setting.called
+ assert mock_boolean_setting.called
- pgwui_server_init.validate_setting_values([], {})
- assert require_setting_called
- assert boolean_setting_called
+mock_validate_setting_values = testing.make_mock_fixture(
+ pgwui_server_init, 'validate_setting_values')
# do_validate_hmac()
assert result is False
+mock_do_validate_hmac = testing.make_mock_fixture(
+ pgwui_server_init, 'do_validate_hmac')
+
+
# validate_hmac()
-def test_validate_hmac_unvalidated(monkeypatch):
+def test_validate_hmac_unvalidated(mock_do_validate_hmac):
'''No error is returned when hmac validation is off'''
- monkeypatch.setattr(pgwui_server_init, 'do_validate_hmac',
- lambda *args: False)
+ mock_do_validate_hmac.return_value = False
errors = []
pgwui_server_init.validate_hmac(errors, {})
assert errors == []
-def test_validate_hmac_success(monkeypatch):
+def test_validate_hmac_success(mock_do_validate_hmac):
'''No error is returned when hmac is validated an the right length'''
- monkeypatch.setattr(pgwui_server_init, 'do_validate_hmac',
- lambda *args: True)
+ mock_do_validate_hmac.return_value = True
errors = []
pgwui_server_init.validate_hmac(
errors, {'session.secret': 'x' * pgwui_server_init.HMAC_LEN})
assert errors == []
-def test_validate_hmac_missing(monkeypatch):
+def test_validate_hmac_missing(mock_do_validate_hmac):
'''Deliver error when hmac is validated and missing'''
- monkeypatch.setattr(pgwui_server_init, 'do_validate_hmac',
- lambda *args: True)
+ mock_do_validate_hmac.return_value = True
errors = []
pgwui_server_init.validate_hmac(errors, {})
assert isinstance(errors[0], pgwui_server_init.NoHMACError)
-def test_validate_hmac_length(monkeypatch):
+def test_validate_hmac_length(mock_do_validate_hmac):
'''Deliver error when hmac is validated and the wrong length'''
- monkeypatch.setattr(pgwui_server_init, 'do_validate_hmac',
- lambda *args: True)
+ mock_do_validate_hmac.return_value = True
errors = []
pgwui_server_init.validate_hmac(errors, {'session.secret': ''})
assert isinstance(errors[0], pgwui_server_init.HMACLengthError)
+mock_validate_hmac = testing.make_mock_fixture(
+ pgwui_server_init, 'validate_hmac')
+
+
# validate_literal_column_headings()
def test_validate_literal_column_headings_nosetting():
errors[0], pgwui_server_init.BadLiteralColumnHeadingsError)
+mock_validate_literal_column_headings = testing.make_mock_fixture(
+ pgwui_server_init, 'validate_literal_column_headings')
+
+
# validate_settings()
-def test_validate_settings(monkeypatch):
+def test_validate_settings(mock_abort_on_bad_setting,
+ mock_validate_setting_values,
+ mock_validate_hmac):
'''Calls abort_on_bad_setting() for each key in setting
'''
- count = 0
-
- def mock_abort_on_bad_setting(*args):
- nonlocal count
- count += 1
-
- monkeypatch.setattr(pgwui_server_init, 'abort_on_bad_setting',
- mock_abort_on_bad_setting)
- monkeypatch.setattr(pgwui_server_init, 'validate_setting_values',
- lambda *args: None)
- monkeypatch.setattr(pgwui_server_init, 'validate_hmac',
- lambda *args: None)
settings = {'key1': 'value1',
'key2': 'value2'}
errors = []
- pgwui_server_init.validate_settings(errors, settings)
- assert count == len(settings)
+ pgwui_server_init.validate_settings(errors, settings, [])
+
+ assert mock_validate_setting_values.called
+ assert mock_validate_hmac.called
+ assert mock_abort_on_bad_setting.call_count == len(settings)
+
+
+mock_validate_settings = testing.make_mock_fixture(
+ pgwui_server_init, 'validate_settings')
# exit_reporting_errors()
assert errlines[1] != 'three'
+mock_exit_reporting_errors = testing.make_mock_fixture(
+ pgwui_server_init, 'exit_reporting_errors')
+
+
# exit_on_invalid_settings()
-def test_exit_on_invalid_settings_invalid(monkeypatch):
+def test_exit_on_invalid_settings_invalid(monkeypatch,
+ mock_exit_reporting_errors):
'''Calls validate_settings and exit_reporting_errors() when
setting is invalid
'''
- def mock_validate_settings(errors, settings):
+ def mock_validate_settings(errors, settings, components):
errors.append('error1')
- exit_reporting_errors_called = False
-
- def mock_exit_reporting_errors(errors):
- nonlocal exit_reporting_errors_called
- exit_reporting_errors_called = True
-
monkeypatch.setattr(pgwui_server_init, 'validate_settings',
mock_validate_settings)
- monkeypatch.setattr(pgwui_server_init, 'exit_reporting_errors',
- mock_exit_reporting_errors)
- pgwui_server_init.exit_on_invalid_settings({})
+ pgwui_server_init.exit_on_invalid_settings({}, [])
- assert exit_reporting_errors_called
+ assert mock_exit_reporting_errors.called
-def test_exit_on_invalid_settings_valid(monkeypatch):
+def test_exit_on_invalid_settings_valid(mock_validate_settings):
'''Returns, without exiting, when all settings are valid
'''
- def mock_validate_settings(errors, settings):
- pass
+ pgwui_server_init.exit_on_invalid_settings({}, [])
- monkeypatch.setattr(pgwui_server_init, 'validate_settings',
- mock_validate_settings)
+ assert True
- pgwui_server_init.exit_on_invalid_settings({})
- assert True
+mock_exit_on_invalid_settings = testing.make_mock_fixture(
+ pgwui_server_init, 'exit_on_invalid_settings')
# parse_assignments()
])
-# find_pgwui_components()
-
-def test_find_pgwui_components(monkeypatch):
- '''Returns list of entry points via iter_entry_points()
- '''
- entry_points = ['a', 'b', 'c']
-
- class MockEntryPoint():
- def __init__(self, val):
- self.__name__ = val
-
- def resolve(self):
- return self
-
- class MockPkgResources():
- def iter_entry_points(*args):
- return [MockEntryPoint(name) for name in entry_points]
+mock_parse_assignments = testing.make_mock_fixture(
+ pgwui_server_init, 'parse_assignments')
- monkeypatch.setattr(
- pgwui_server_init, 'pkg_resources', MockPkgResources())
- result = pgwui_server_init.find_pgwui_components()
+# autoconfigurable_components()
- assert result == entry_points
-
-
-# autoconfig_components()
-
-def test_autoconfig_components_no_autoconfig(monkeypatch):
+def test_autoconfiguable_components_no_autoconfig():
'''When the settings have no pgwui.autoconfigure return an empty list
'''
- monkeypatch.setattr(pgwui_server_init, 'find_pgwui_components',
- lambda *args: [])
+ test_components = ['some', 'components']
- result = pgwui_server_init.autoconfig_components({})
+ result = pgwui_server_init.autoconfigurable_components({}, test_components)
assert result == []
-def test_autoconfig_components_log_info(monkeypatch, caplog):
+def test_autoconfigurable_components_log_info(caplog):
'''When pyramid.include is in the settings an INFO message is logged
'''
- monkeypatch.setattr(pgwui_server_init, 'find_pgwui_components',
- lambda *args: [])
-
caplog.set_level(logging.INFO)
- pgwui_server_init.autoconfig_components({'pgwui.autoconfigure': True,
- 'pyramid.include': None})
+ pgwui_server_init.autoconfigurable_components(
+ {'pgwui.autoconfigure': True, 'pyramid.include': None}, [])
logs = caplog.record_tuples
assert level == logging.INFO
-def test_autoconfig_components_find_pgwui_components_called(monkeypatch):
- '''When pyramid.include is in the settings an INFO message is logged
+def test_autoconfigurable_components_components_returned():
+ '''The suppiled components are returned when autoconfigure is True
'''
- find_pgwui_components_called = False
+ test_components = ['some', 'components']
- def mock_find_pgwui_components(*args):
- nonlocal find_pgwui_components_called
- find_pgwui_components_called = True
+ result = pgwui_server_init.autoconfigurable_components(
+ {'pgwui.autoconfigure': True}, test_components)
- monkeypatch.setattr(pgwui_server_init, 'find_pgwui_components',
- mock_find_pgwui_components)
+ assert result == test_components
- pgwui_server_init.autoconfig_components({'pgwui.autoconfigure': True,
- 'mock_pgwui_component': 'foo'})
- assert find_pgwui_components_called
+mock_autoconfigurable_components = testing.make_mock_fixture(
+ pgwui_server_init, 'autoconfigurable_components')
# add_routes()
-def test_add_routes_empty():
+def test_add_routes_empty(mock_add_route):
'''When there is no pgwui.routes setting nothing gets added'''
- config = MockConfig()
- pgwui_server_init.add_routes(config, {})
- assert config.add_route_called == 0
+ with pyramid.testing.testConfig() as config:
+ mocked_add_route = mock_add_route(config)
+ pgwui_server_init.add_routes(config, {})
+
+ assert not mocked_add_route.called
-def test_add_routes_notempty(monkeypatch):
+def test_add_routes_notempty(mock_add_route, mock_parse_assignments):
'''When there is a pgwui.routes setting config.add_route() is called
for each route'''
- config = MockConfig()
- monkeypatch.setattr(pgwui_server_init, 'parse_assignments',
- lambda *args: [('name1', 'route1'),
- ('name2', 'route2')])
- pgwui_server_init.add_routes(config, {'pgwui.routes': ''})
- assert config.add_route_called == 2
+ test_routes = [('name1', 'route1'),
+ ('name2', 'route2')]
+ mock_parse_assignments.return_value = test_routes
+ with pyramid.testing.testConfig() as config:
+ mocked_add_route = mock_add_route(config)
+ pgwui_server_init.add_routes(config, {'pgwui.routes': ''})
+ assert mocked_add_route.call_count == len(test_routes)
-# pgwui_server_config()
-def test_pgwui_server_config(monkeypatch):
- '''Returns a configuration'''
- monkeypatch.setattr(pgwui_server_init, 'exit_on_invalid_settings',
- lambda *args: True)
- monkeypatch.setattr(pgwui_server_init, 'autoconfig_components',
- lambda *args: ['pgwui_mock_component_name'])
+mock_add_routes = testing.make_mock_fixture(
+ pgwui_server_init, 'add_routes')
+
+
+# apply_component_defaults()
+
+
+def test_apply_component_defaults(monkeypatch,
+ mock_autoconfigurable_components,
+ mock_add_routes):
+ mock_autoconfigurable_components.return_value = \
+ ['pgwui_mock_component_name']
monkeypatch.setattr(pgwui_server_init, 'Configurator',
MockConfigurator)
- monkeypatch.setattr(pgwui_server_init, 'add_routes',
- lambda *args: None)
- result = pgwui_server_init.pgwui_server_config({})
+ result = pgwui_server_init.apply_component_defaults({}, [])
assert isinstance(result, MockConfigurator)
+mock_apply_component_defaults = testing.make_mock_fixture(
+ pgwui_server_init, 'apply_component_defaults')
+
+
+# pgwui_server_config()
+
+def test_pgwui_server_config(
+ mock_find_pgwui_components,
+ mock_apply_component_defaults, mock_exit_on_invalid_settings):
+ '''Returns a configuration'''
+ test_configurator = 'test configurator'
+ mock_apply_component_defaults.return_value = test_configurator
+
+ result = pgwui_server_init.pgwui_server_config({})
+
+ assert result == test_configurator
+
+
# main()
def test_main(monkeypatch):
'''Returns a wsgi app'''