Commit 3f6fec46 by Matt Drayer

mattdrayer/multitenant-fulfillment: Add site-specific configuration support

* mattdrayer: Enable site-level overrides for all settings
* mattdrayer: Update edx-lint to 0.5.1
* mattdrayer: Increment minor version
parent 7d0c31c8
......@@ -47,3 +47,7 @@ JWT_ISSUER = None
ECOMMERCE_SERVICE_USERNAME = 'ecommerce_worker'
# END AUTHENTICATION
# Site Overrides provide support for site/partner-specific configuration settings where applicable
# For example, the ECOMMERCE_API_ROOT value is different from one ecommerce site to the next
SITE_OVERRIDES = None
......@@ -20,9 +20,14 @@ logger_config = get_logger_config(debug=True, dev_env=True, local_loglevel='DEBU
dictConfig(logger_config)
# END LOGGING
# AUTHENTICATION
JWT_SECRET_KEY = 'test-key'
JWT_ISSUER = 'ecommerce_worker'
ECOMMERCE_SERVICE_USERNAME = 'service'
# END AUTHENTICATION
# SITE-SPECIFIC CONFIGURATION OVERRIDES
SITE_OVERRIDES = {}
......@@ -11,7 +11,7 @@ logger = get_task_logger(__name__) # pylint: disable=invalid-name
@shared_task(bind=True, ignore_result=True)
def fulfill_order(self, order_number):
def fulfill_order(self, order_number, site_code=None):
"""Fulfills an order.
Arguments:
......@@ -20,11 +20,11 @@ def fulfill_order(self, order_number):
Returns:
None
"""
ecommerce_api_root = get_configuration('ECOMMERCE_API_ROOT')
max_fulfillment_retries = get_configuration('MAX_FULFILLMENT_RETRIES')
signing_key = get_configuration('JWT_SECRET_KEY')
issuer = get_configuration('JWT_ISSUER')
service_username = get_configuration('ECOMMERCE_SERVICE_USERNAME')
ecommerce_api_root = get_configuration('ECOMMERCE_API_ROOT', site_code=site_code)
max_fulfillment_retries = get_configuration('MAX_FULFILLMENT_RETRIES', site_code=site_code)
signing_key = get_configuration('JWT_SECRET_KEY', site_code=site_code)
issuer = get_configuration('JWT_ISSUER', site_code=site_code)
service_username = get_configuration('ECOMMERCE_SERVICE_USERNAME', site_code=site_code)
api = EdxRestApiClient(ecommerce_api_root, signing_key=signing_key, issuer=issuer, username=service_username)
try:
......
"""
Tests for unversioned packages and modules
"""
""" Test coverage for ecommerce_worker/utils.py """
from unittest import TestCase
import ddt
import mock
from ecommerce_worker.configuration.test import ECOMMERCE_API_ROOT
from ecommerce_worker.utils import get_configuration
@ddt.ddt
class GetConfigurationTests(TestCase):
"""Tests covering the get_configuration operation."""
SITE_OVERRIDES_MODULE = 'ecommerce_worker.configuration.test.SITE_OVERRIDES'
TEST_SETTING = 'ECOMMERCE_API_ROOT'
OVERRIDES_DICT = {
'openedx': {'ECOMMERCE_API_ROOT': 'http://openedx.org'},
'test': {'ECOMMERCE_API_ROOT': 'http://example.com'},
'novalue': {'ECOMMERCE_API_ROOT': None},
'emptydict': {}
}
def test_configuration_no_site_overrides(self):
test_setting = get_configuration(self.TEST_SETTING)
self.assertEqual(test_setting, ECOMMERCE_API_ROOT)
def test_configuration_no_site_code_specified(self):
with mock.patch.dict(self.SITE_OVERRIDES_MODULE, self.OVERRIDES_DICT):
test_setting = get_configuration(self.TEST_SETTING)
self.assertEqual(test_setting, ECOMMERCE_API_ROOT)
@ddt.data('openedx', 'test')
def test_configuration_valid_site_code_dict_value(self, site_code):
"""
Confirm that valid SITE_OVERRIDES parameters are correctly returned
"""
with mock.patch.dict(self.SITE_OVERRIDES_MODULE, self.OVERRIDES_DICT):
test_setting = get_configuration(self.TEST_SETTING, site_code=site_code)
self.assertEqual(test_setting, self.OVERRIDES_DICT[site_code][self.TEST_SETTING])
@ddt.data(None, 'invalid', 'emptydict', 'novalue')
def test_configuration_no_site_code_matched(self, site_code):
"""
Test various states of SITE_OVERRIDES to ensure all branches (ie, use cases) are covered
"""
with mock.patch.dict(self.SITE_OVERRIDES_MODULE, self.OVERRIDES_DICT):
test_setting = get_configuration(self.TEST_SETTING, site_code=site_code)
self.assertEqual(test_setting, ECOMMERCE_API_ROOT)
......@@ -5,15 +5,19 @@ import sys
from ecommerce_worker.configuration import CONFIGURATION_MODULE
def get_configuration(variable):
"""Get a value from configuration.
def get_configuration(variable, site_code=None):
"""
Get a value from configuration.
Retrieves the value corresponding to the given variable from the
configuration module currently in use by the app.
Retrieves the value corresponding to the given variable from the configuration module
currently in use by the app. Specify a site_code value to check for a site-specific override.
Arguments:
variable (str): The name of a variable from the configuration module.
Keyword Arguments:
site_code (str): The SITE_OVERRIDES key to inspect for site-specific values
Returns:
The value corresponding to the variable, or None if the variable is not found.
"""
......@@ -25,7 +29,16 @@ def get_configuration(variable):
__import__(name)
module = sys.modules[name]
value = getattr(module, variable, None)
if value is None:
# Locate the setting in the specified module, then attempt to apply a site-specific override
setting_value = getattr(module, variable, None)
site_overrides = getattr(module, 'SITE_OVERRIDES', None)
if site_overrides:
site_specific_overrides = site_overrides.get(site_code)
if site_specific_overrides:
override_value = site_specific_overrides.get(variable)
if override_value:
setting_value = override_value
if setting_value is None:
raise RuntimeError('Worker is improperly configured: {} is unset in {}.'.format(variable, module))
return value
return setting_value
......@@ -3,7 +3,7 @@
coverage==4.0.3
ddt==1.0.1
edx-lint==0.4.3
edx-lint==0.5.1
httpretty==0.8.10
mock==1.3.0
nose==1.3.7
......
......@@ -6,7 +6,7 @@ with open('README.rst') as readme:
setup(
name='edx-ecommerce-worker',
version='0.3.3',
version='0.4.0',
description='Celery tasks supporting the operations of edX\'s ecommerce service',
long_description=long_description,
classifiers=[
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment