diff --git a/.readthedocs.yml b/.readthedocs.yml index 9187bed8..a79cc7fc 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,12 +5,16 @@ # Required version: 2 +build: + os: "ubuntu-22.04" + tools: + python: "3.8" + # Build documentation in the docs/ directory with Sphinx sphinx: configuration: docs/conf.py fail_on_warning: true python: - version: 3.8 install: - requirements: requirements/doc.txt diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d485cef8..b833062d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,6 +17,12 @@ Changed ~~~~~~~ * Re-licensed this repository from AGPL 3.0 to Apache 2.0 +[8.6.0] - 2023-08-28 +-------------------- +Added +~~~~~ +* Added generic handler to allow producing to event bus via django settings. + [8.5.0] - 2023-08-08 -------------------- Changed diff --git a/docs/how-tos/adding-events-to-event-bus.rst b/docs/how-tos/adding-events-to-event-bus.rst index 88272c28..7373bed8 100644 --- a/docs/how-tos/adding-events-to-event-bus.rst +++ b/docs/how-tos/adding-events-to-event-bus.rst @@ -7,8 +7,35 @@ to use the Open edX Event Bus. Here, we list useful information about adding a new event to the event bus: - `How to start using the Event Bus`_ -- `Sample pull request adding new Open edX Events to the Event Bus`_ .. _How to start using the Event Bus: https://openedx.atlassian.net/wiki/spaces/AC/pages/3508699151/How+to+start+using+the+Event+Bus -.. _Sample pull request adding new Open edX Events to the Event Bus: https://github.com/openedx/edx-platform/pull/31350 + + +Producing to event bus +^^^^^^^^^^^^^^^^^^^^^^ + +In the producing/host application, include ``openedx_events`` in ``INSTALLED_APPS`` settings and add ``EVENT_BUS_PRODUCER_CONFIG`` setting. For example, below snippet is to push ``XBLOCK_PUBLISHED`` to two different topics and ``XBLOCK_DELETED`` signal to one topic in event bus. + +.. code-block:: python + + # .. setting_name: EVENT_BUS_PRODUCER_CONFIG + # .. setting_default: {} + # .. setting_description: Dictionary of event_types mapped to lists of dictionaries containing topic related configuration. + # Each topic configuration dictionary contains + # * a topic/stream name called `topic` where the event will be pushed to. + # * a flag called `enabled` denoting whether the event will be published to the topic. + # * `event_key_field` which is a period-delimited string path to event data field to use as event key. + # Note: The topic names should not include environment prefix as it will be dynamically added based on + # EVENT_BUS_TOPIC_PREFIX setting. + EVENT_BUS_PRODUCER_CONFIG = { + 'org.openedx.content_authoring.xblock.published.v1': [ + {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': True}, + {'topic': 'content-authoring-xblock-published', 'event_key_field': 'xblock_info.usage_key', 'enabled': True}, + ], + 'org.openedx.content_authoring.xblock.deleted.v1': [ + {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key', 'enabled': True}, + ], + } + +The ``EVENT_BUS_PRODUCER_CONFIG`` is read by openedx_events and a handler is attached which does the leg work of reading the configuration again and pushing to appropriate handlers. diff --git a/openedx_events/__init__.py b/openedx_events/__init__.py index 6d551d4c..3feb7fdf 100644 --- a/openedx_events/__init__.py +++ b/openedx_events/__init__.py @@ -5,4 +5,4 @@ more information about the project. """ -__version__ = "8.5.0" +__version__ = "8.6.0" diff --git a/openedx_events/apps.py b/openedx_events/apps.py index c908d73a..0219eb95 100644 --- a/openedx_events/apps.py +++ b/openedx_events/apps.py @@ -3,6 +3,28 @@ """ from django.apps import AppConfig +from django.conf import settings + +from openedx_events.event_bus import get_producer +from openedx_events.exceptions import ProducerConfigurationError +from openedx_events.tooling import OpenEdxPublicSignal, load_all_signals + + +def general_signal_handler(sender, signal, **kwargs): # pylint: disable=unused-argument + """ + Signal handler for publishing events to configured event bus. + """ + configurations = getattr(settings, "EVENT_BUS_PRODUCER_CONFIG", {}).get(signal.event_type, ()) + event_data = {key: kwargs.get(key) for key in signal.init_data} + for configuration in configurations: + if configuration["enabled"]: + get_producer().send( + signal=signal, + topic=configuration["topic"], + event_key_field=configuration["event_key_field"], + event_data=event_data, + event_metadata=kwargs["metadata"], + ) class OpenedxEventsConfig(AppConfig): @@ -10,4 +32,60 @@ class OpenedxEventsConfig(AppConfig): Configuration for the openedx_events Django application. """ - name = 'openedx_events' + name = "openedx_events" + + def _get_validated_signal_config(self, event_type, configurations): + """ + Validate signal configuration format. + + Raises: + ProducerConfigurationError: If configuration is not valid. + """ + if not isinstance(configurations, list) and not isinstance(configurations, tuple): + raise ProducerConfigurationError( + event_type=event_type, + message="Configuration for event_types should be a list or a tuple of dictionaries" + ) + try: + signal = OpenEdxPublicSignal.get_signal_by_type(event_type) + except KeyError as exc: + raise ProducerConfigurationError(message=f"No OpenEdxPublicSignal of type: '{event_type}'.") from exc + for configuration in configurations: + if not isinstance(configuration, dict): + raise ProducerConfigurationError( + event_type=event_type, + message="One of the configuration object is not a dictionary" + ) + expected_keys = {"topic": str, "event_key_field": str, "enabled": bool} + for expected_key, expected_type in expected_keys.items(): + if expected_key not in configuration: + raise ProducerConfigurationError( + event_type=event_type, + message=f"One of the configuration object is missing '{expected_key}' key." + ) + if not isinstance(configuration[expected_key], expected_type): + raise ProducerConfigurationError( + event_type=event_type, + message=(f"Expected type: {expected_type} for '{expected_key}', " + f"found: {type(configuration[expected_key])}") + ) + return signal + + def ready(self): + """ + Read `EVENT_BUS_PRODUCER_CONFIG` setting and connects appropriate handlers to the events based on it. + + Raises: + ProducerConfigurationError: If `EVENT_BUS_PRODUCER_CONFIG` is not valid. + """ + load_all_signals() + signals_config = getattr(settings, "EVENT_BUS_PRODUCER_CONFIG", {}) + if not isinstance(signals_config, dict): + raise ProducerConfigurationError( + message=("Setting 'EVENT_BUS_PRODUCER_CONFIG' should be a dictionary with event_type as" + " key and list or tuple of config dictionaries as values") + ) + for event_type, configurations in signals_config.items(): + signal = self._get_validated_signal_config(event_type, configurations) + signal.connect(general_signal_handler) + return super().ready() diff --git a/openedx_events/exceptions.py b/openedx_events/exceptions.py index 8b864252..e75f32bb 100644 --- a/openedx_events/exceptions.py +++ b/openedx_events/exceptions.py @@ -67,3 +67,23 @@ def __init__(self, event_type="", message=""): event_type=event_type, message=message ) ) + + +class ProducerConfigurationError(OpenEdxEventException): + """ + Describes errors that occurs while validating format of producer signal configuration. + """ + + def __init__(self, event_type="", message=""): + """ + Init method for ProducerConfigurationError custom exception class. + + Arguments: + event_type (str): name of the event raising the exception. + message (str): message describing why the exception was raised. + """ + super().__init__( + message="ProducerConfigurationError {event_type}: {message}".format( + event_type=event_type, message=message + ) + ) diff --git a/openedx_events/tests/test_producer_config.py b/openedx_events/tests/test_producer_config.py new file mode 100644 index 00000000..ee84bd79 --- /dev/null +++ b/openedx_events/tests/test_producer_config.py @@ -0,0 +1,125 @@ +""" +Test for producer configuration. +""" +from unittest.mock import Mock, patch + +import ddt +import pytest +from django.apps import apps +from django.test import TestCase, override_settings + +from openedx_events.content_authoring.data import XBlockData +from openedx_events.content_authoring.signals import XBLOCK_DELETED, XBLOCK_PUBLISHED +from openedx_events.exceptions import ProducerConfigurationError + + +@ddt.ddt +class ProducerConfiguratonTest(TestCase): + """ + Tests to make sure EVENT_BUS_PRODUCER_CONFIG setting connects required signals to appropriate handlers. + + Attributes: + xblock_info: dummy XBlockData. + """ + def setUp(self) -> None: + super().setUp() + self.xblock_info = XBlockData( + usage_key='block-v1:edx+DemoX+Demo_course+type@video+block@UaEBjyMjcLW65gaTXggB93WmvoxGAJa0JeHRrDThk', + block_type='video', + ) + + @patch('openedx_events.apps.get_producer') + def test_enabled_disabled_events(self, mock_producer): + """ + Check whether XBLOCK_PUBLISHED is connected to the handler and the handler only publishes enabled events. + + Args: + mock_producer: mock get_producer to inspect the arguments. + """ + mock_send = Mock() + mock_producer.return_value = mock_send + # XBLOCK_PUBLISHED has three configurations where 2 configurations have set enabled as True. + XBLOCK_PUBLISHED.send_event(xblock_info=self.xblock_info) + mock_send.send.assert_called() + mock_send.send.call_count = 2 + + # check that call_args_list only consists of enabled topics. + call_args = mock_send.send.call_args_list[0][1] + self.assertDictContainsSubset( + {'topic': 'content-authoring-xblock-lifecycle', 'event_key_field': 'xblock_info.usage_key'}, + call_args + ) + call_args = mock_send.send.call_args_list[1][1] + self.assertDictContainsSubset( + {'topic': 'content-authoring-all-status', 'event_key_field': 'xblock_info.usage_key'}, + call_args + ) + + @patch('openedx_events.apps.get_producer') + @override_settings(EVENT_BUS_PRODUCER_CONFIG={}) + def test_events_not_in_config(self, mock_producer): + """ + Check whether events not included in the configuration are not published as expected. + + Args: + mock_producer: mock get_producer to inspect the arguments. + """ + mock_send = Mock() + mock_producer.return_value = mock_send + XBLOCK_PUBLISHED.send_event(xblock_info=self.xblock_info) + mock_producer.assert_not_called() + mock_send.send.assert_not_called() + + def test_configuration_is_validated(self): + """ + Check whether EVENT_BUS_PRODUCER_CONFIG setting is validated before connecting handlers. + """ + with override_settings(EVENT_BUS_PRODUCER_CONFIG=[]): + with pytest.raises(ProducerConfigurationError, match="should be a dictionary"): + apps.get_app_config("openedx_events").ready() + + with override_settings(EVENT_BUS_PRODUCER_CONFIG={"invalid.event.type": []}): + with pytest.raises(ProducerConfigurationError, match="No OpenEdxPublicSignal of type"): + apps.get_app_config("openedx_events").ready() + + with override_settings(EVENT_BUS_PRODUCER_CONFIG={"org.openedx.content_authoring.xblock.deleted.v1": ""}): + with pytest.raises(ProducerConfigurationError, match="should be a list or a tuple"): + apps.get_app_config("openedx_events").ready() + + with override_settings(EVENT_BUS_PRODUCER_CONFIG={"org.openedx.content_authoring.xblock.deleted.v1": [""]}): + with pytest.raises(ProducerConfigurationError, match="object is not a dictionary"): + apps.get_app_config("openedx_events").ready() + + with override_settings( + EVENT_BUS_PRODUCER_CONFIG={ + "org.openedx.content_authoring.xblock.deleted.v1": [{"topic": "some", "enabled": True}] + } + ): + with pytest.raises(ProducerConfigurationError, match="missing 'event_key_field' key."): + apps.get_app_config("openedx_events").ready() + + with override_settings( + EVENT_BUS_PRODUCER_CONFIG={ + "org.openedx.content_authoring.xblock.deleted.v1": [ + {"topic": "some", "enabled": 1, "event_key_field": "some"} + ] + } + ): + with pytest.raises( + ProducerConfigurationError, + match="Expected type: for 'enabled', found: " + ): + apps.get_app_config("openedx_events").ready() + + @patch('openedx_events.apps.get_producer') + def test_event_data_key_in_handler(self, mock_producer): + """ + Check whether event_data is constructed properly in handlers. + """ + mock_send = Mock() + mock_producer.return_value = mock_send + XBLOCK_DELETED.send_event(xblock_info=self.xblock_info) + mock_send.send.assert_called_once() + + call_args = mock_send.send.call_args_list[0][1] + self.assertIn("xblock_info", call_args["event_data"]) diff --git a/requirements/base.txt b/requirements/base.txt index f3811b36..2f2e2cfc 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -12,9 +12,9 @@ django==3.2.20 # via # -c requirements/common_constraints.txt # -r requirements/base.in -edx-opaque-keys[django]==2.3.0 +edx-opaque-keys[django]==2.5.0 # via -r requirements/base.in -fastavro==1.8.0 +fastavro==1.8.2 # via -r requirements/base.in pbr==5.11.1 # via stevedore @@ -27,4 +27,6 @@ sqlparse==0.4.4 stevedore==5.1.0 # via edx-opaque-keys typing-extensions==4.7.1 - # via asgiref + # via + # asgiref + # edx-opaque-keys diff --git a/requirements/ci.txt b/requirements/ci.txt index 1dcfacae..534b472b 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -4,7 +4,7 @@ # # make upgrade # -distlib==0.3.6 +distlib==0.3.7 # via virtualenv filelock==3.12.2 # via @@ -12,9 +12,9 @@ filelock==3.12.2 # virtualenv packaging==23.1 # via tox -platformdirs==3.9.1 +platformdirs==3.10.0 # via virtualenv -pluggy==1.2.0 +pluggy==1.3.0 # via tox py==1.11.0 # via tox @@ -26,5 +26,5 @@ tox==3.28.0 # via # -c requirements/common_constraints.txt # -r requirements/ci.in -virtualenv==20.24.0 +virtualenv==20.24.3 # via tox diff --git a/requirements/dev.txt b/requirements/dev.txt index 5d19b0da..8aef2455 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -23,7 +23,7 @@ build==0.10.0 # via # -r requirements/pip-tools.txt # pip-tools -certifi==2023.5.7 +certifi==2023.7.22 # via # -r requirements/quality.txt # requests @@ -31,13 +31,13 @@ cffi==1.15.1 # via # -r requirements/quality.txt # cryptography -chardet==5.1.0 +chardet==5.2.0 # via diff-cover charset-normalizer==3.2.0 # via # -r requirements/quality.txt # requests -click==8.1.5 +click==8.1.7 # via # -r requirements/pip-tools.txt # -r requirements/quality.txt @@ -49,15 +49,15 @@ click-log==0.4.0 # via # -r requirements/quality.txt # edx-lint -code-annotations==1.3.0 +code-annotations==1.5.0 # via # -r requirements/quality.txt # edx-lint -coverage[toml]==7.2.7 +coverage[toml]==7.3.0 # via # -r requirements/quality.txt # pytest-cov -cryptography==41.0.2 +cryptography==41.0.3 # via # -r requirements/quality.txt # secretstorage @@ -65,11 +65,11 @@ ddt==1.6.0 # via -r requirements/quality.txt diff-cover==7.7.0 # via -r requirements/dev.in -dill==0.3.6 +dill==0.3.7 # via # -r requirements/quality.txt # pylint -distlib==0.3.6 +distlib==0.3.7 # via # -r requirements/ci.txt # virtualenv @@ -83,13 +83,13 @@ docutils==0.20.1 # readme-renderer edx-lint==5.3.4 # via -r requirements/quality.txt -edx-opaque-keys[django]==2.3.0 +edx-opaque-keys[django]==2.5.0 # via -r requirements/quality.txt -exceptiongroup==1.1.2 +exceptiongroup==1.1.3 # via # -r requirements/quality.txt # pytest -fastavro==1.8.0 +fastavro==1.8.2 # via -r requirements/quality.txt filelock==3.12.2 # via @@ -105,7 +105,7 @@ importlib-metadata==6.8.0 # -r requirements/quality.txt # keyring # twine -importlib-resources==6.0.0 +importlib-resources==6.0.1 # via # -r requirements/quality.txt # keyring @@ -155,7 +155,7 @@ mdurl==0.1.2 # via # -r requirements/quality.txt # markdown-it-py -more-itertools==9.1.0 +more-itertools==10.1.0 # via # -r requirements/quality.txt # jaraco-classes @@ -171,19 +171,19 @@ pbr==5.11.1 # via # -r requirements/quality.txt # stevedore -pip-tools==7.0.0 +pip-tools==7.3.0 # via -r requirements/pip-tools.txt pkginfo==1.9.6 # via # -r requirements/quality.txt # twine -platformdirs==3.9.1 +platformdirs==3.10.0 # via # -r requirements/ci.txt # -r requirements/quality.txt # pylint # virtualenv -pluggy==1.2.0 +pluggy==1.3.0 # via # -r requirements/ci.txt # -r requirements/quality.txt @@ -194,7 +194,7 @@ py==1.11.0 # via # -r requirements/ci.txt # tox -pycodestyle==2.10.0 +pycodestyle==2.11.0 # via -r requirements/quality.txt pycparser==2.21 # via @@ -202,13 +202,13 @@ pycparser==2.21 # cffi pydocstyle==6.3.0 # via -r requirements/quality.txt -pygments==2.15.1 +pygments==2.16.1 # via # -r requirements/quality.txt # diff-cover # readme-renderer # rich -pylint==2.17.4 +pylint==2.17.5 # via # -r requirements/quality.txt # edx-lint @@ -253,11 +253,11 @@ pytz==2023.3 # via # -r requirements/quality.txt # django -pyyaml==6.0 +pyyaml==6.0.1 # via # -r requirements/quality.txt # code-annotations -readme-renderer==40.0 +readme-renderer==41.0 # via # -r requirements/quality.txt # twine @@ -274,7 +274,7 @@ rfc3986==2.0.0 # via # -r requirements/quality.txt # twine -rich==13.4.2 +rich==13.5.2 # via # -r requirements/quality.txt # twine @@ -318,7 +318,7 @@ tomli==2.0.1 # pyproject-hooks # pytest # tox -tomlkit==0.11.8 +tomlkit==0.12.1 # via # -r requirements/quality.txt # pylint @@ -327,7 +327,7 @@ tox==3.28.0 # -c requirements/common_constraints.txt # -r requirements/ci.txt # tox-battery -tox-battery==0.6.1 +tox-battery==0.6.2 # via -r requirements/dev.in twine==4.0.2 # via -r requirements/quality.txt @@ -336,14 +336,15 @@ typing-extensions==4.7.1 # -r requirements/quality.txt # asgiref # astroid + # edx-opaque-keys # pylint # rich -urllib3==2.0.3 +urllib3==2.0.4 # via # -r requirements/quality.txt # requests # twine -virtualenv==20.24.0 +virtualenv==20.24.3 # via # -r requirements/ci.txt # tox @@ -351,7 +352,7 @@ webencodings==0.5.1 # via # -r requirements/quality.txt # bleach -wheel==0.40.0 +wheel==0.41.2 # via # -r requirements/pip-tools.txt # pip-tools diff --git a/requirements/doc.txt b/requirements/doc.txt index ce268b05..5b9ac7a6 100644 --- a/requirements/doc.txt +++ b/requirements/doc.txt @@ -20,25 +20,25 @@ bleach==6.0.0 # via readme-renderer build==0.10.0 # via -r requirements/doc.in -certifi==2023.5.7 +certifi==2023.7.22 # via requests cffi==1.15.1 # via cryptography charset-normalizer==3.2.0 # via requests -click==8.1.5 +click==8.1.7 # via # -r requirements/test.txt # code-annotations -code-annotations==1.3.0 +code-annotations==1.5.0 # via -r requirements/test.txt colorama==0.4.6 # via sphinx-autobuild -coverage[toml]==7.2.7 +coverage[toml]==7.3.0 # via # -r requirements/test.txt # pytest-cov -cryptography==41.0.2 +cryptography==41.0.3 # via secretstorage ddt==1.6.0 # via -r requirements/test.txt @@ -55,13 +55,13 @@ docutils==0.19 # readme-renderer # restructuredtext-lint # sphinx -edx-opaque-keys[django]==2.3.0 +edx-opaque-keys[django]==2.5.0 # via -r requirements/test.txt -exceptiongroup==1.1.2 +exceptiongroup==1.1.3 # via # -r requirements/test.txt # pytest -fastavro==1.8.0 +fastavro==1.8.2 # via -r requirements/test.txt idna==3.4 # via requests @@ -72,7 +72,7 @@ importlib-metadata==6.8.0 # keyring # sphinx # twine -importlib-resources==6.0.0 +importlib-resources==6.0.1 # via keyring iniconfig==2.0.0 # via @@ -101,7 +101,7 @@ markupsafe==2.1.3 # jinja2 mdurl==0.1.2 # via markdown-it-py -more-itertools==9.1.0 +more-itertools==10.1.0 # via jaraco-classes packaging==23.1 # via @@ -116,7 +116,7 @@ pbr==5.11.1 # stevedore pkginfo==1.9.6 # via twine -pluggy==1.2.0 +pluggy==1.3.0 # via # -r requirements/test.txt # pytest @@ -124,7 +124,7 @@ pycparser==2.21 # via cffi pydata-sphinx-theme==0.12.0 # via sphinx-book-theme -pygments==2.15.1 +pygments==2.16.1 # via # doc8 # pydata-sphinx-theme @@ -155,12 +155,12 @@ pytz==2023.3 # -r requirements/test.txt # babel # django -pyyaml==6.0 +pyyaml==6.0.1 # via # -r requirements/test.txt # code-annotations # sphinx-book-theme -readme-renderer==40.0 +readme-renderer==41.0 # via twine requests==2.31.0 # via @@ -173,7 +173,7 @@ restructuredtext-lint==1.4.0 # via doc8 rfc3986==2.0.0 # via twine -rich==13.4.2 +rich==13.5.2 # via twine secretstorage==3.3.3 # via keyring @@ -239,7 +239,7 @@ tomli==2.0.1 # doc8 # pyproject-hooks # pytest -tornado==6.3.2 +tornado==6.3.3 # via livereload twine==4.0.2 # via -r requirements/doc.in @@ -247,8 +247,9 @@ typing-extensions==4.7.1 # via # -r requirements/test.txt # asgiref + # edx-opaque-keys # rich -urllib3==2.0.3 +urllib3==2.0.4 # via # requests # twine diff --git a/requirements/pip-tools.txt b/requirements/pip-tools.txt index 5a27e2a1..007ed388 100644 --- a/requirements/pip-tools.txt +++ b/requirements/pip-tools.txt @@ -6,11 +6,11 @@ # build==0.10.0 # via pip-tools -click==8.1.5 +click==8.1.7 # via pip-tools packaging==23.1 # via build -pip-tools==7.0.0 +pip-tools==7.3.0 # via -r requirements/pip-tools.in pyproject-hooks==1.0.0 # via build @@ -18,7 +18,8 @@ tomli==2.0.1 # via # build # pip-tools -wheel==0.40.0 + # pyproject-hooks +wheel==0.41.2 # via pip-tools # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements/pip.txt b/requirements/pip.txt index bd9fb553..13c7e845 100644 --- a/requirements/pip.txt +++ b/requirements/pip.txt @@ -4,11 +4,11 @@ # # make upgrade # -wheel==0.40.0 +wheel==0.41.2 # via -r requirements/pip.in # The following packages are considered to be unsafe in a requirements file: -pip==23.2 +pip==23.2.1 # via -r requirements/pip.in -setuptools==68.0.0 +setuptools==68.1.2 # via -r requirements/pip.in diff --git a/requirements/quality.txt b/requirements/quality.txt index 3aee2586..48155f15 100644 --- a/requirements/quality.txt +++ b/requirements/quality.txt @@ -16,13 +16,13 @@ attrs==23.1.0 # via -r requirements/test.txt bleach==6.0.0 # via readme-renderer -certifi==2023.5.7 +certifi==2023.7.22 # via requests cffi==1.15.1 # via cryptography charset-normalizer==3.2.0 # via requests -click==8.1.5 +click==8.1.7 # via # -r requirements/test.txt # click-log @@ -30,19 +30,19 @@ click==8.1.5 # edx-lint click-log==0.4.0 # via edx-lint -code-annotations==1.3.0 +code-annotations==1.5.0 # via # -r requirements/test.txt # edx-lint -coverage[toml]==7.2.7 +coverage[toml]==7.3.0 # via # -r requirements/test.txt # pytest-cov -cryptography==41.0.2 +cryptography==41.0.3 # via secretstorage ddt==1.6.0 # via -r requirements/test.txt -dill==0.3.6 +dill==0.3.7 # via pylint django==3.2.20 # via @@ -52,13 +52,13 @@ docutils==0.20.1 # via readme-renderer edx-lint==5.3.4 # via -r requirements/quality.in -edx-opaque-keys[django]==2.3.0 +edx-opaque-keys[django]==2.5.0 # via -r requirements/test.txt -exceptiongroup==1.1.2 +exceptiongroup==1.1.3 # via # -r requirements/test.txt # pytest -fastavro==1.8.0 +fastavro==1.8.2 # via -r requirements/test.txt idna==3.4 # via requests @@ -66,7 +66,7 @@ importlib-metadata==6.8.0 # via # keyring # twine -importlib-resources==6.0.0 +importlib-resources==6.0.1 # via keyring iniconfig==2.0.0 # via @@ -100,7 +100,7 @@ mccabe==0.7.0 # via pylint mdurl==0.1.2 # via markdown-it-py -more-itertools==9.1.0 +more-itertools==10.1.0 # via jaraco-classes packaging==23.1 # via @@ -112,23 +112,23 @@ pbr==5.11.1 # stevedore pkginfo==1.9.6 # via twine -platformdirs==3.9.1 +platformdirs==3.10.0 # via pylint -pluggy==1.2.0 +pluggy==1.3.0 # via # -r requirements/test.txt # pytest -pycodestyle==2.10.0 +pycodestyle==2.11.0 # via -r requirements/quality.in pycparser==2.21 # via cffi pydocstyle==6.3.0 # via -r requirements/quality.in -pygments==2.15.1 +pygments==2.16.1 # via # readme-renderer # rich -pylint==2.17.4 +pylint==2.17.5 # via # edx-lint # pylint-celery @@ -163,11 +163,11 @@ pytz==2023.3 # via # -r requirements/test.txt # django -pyyaml==6.0 +pyyaml==6.0.1 # via # -r requirements/test.txt # code-annotations -readme-renderer==40.0 +readme-renderer==41.0 # via twine requests==2.31.0 # via @@ -177,7 +177,7 @@ requests-toolbelt==1.0.0 # via twine rfc3986==2.0.0 # via twine -rich==13.4.2 +rich==13.5.2 # via twine secretstorage==3.3.3 # via keyring @@ -206,7 +206,7 @@ tomli==2.0.1 # coverage # pylint # pytest -tomlkit==0.11.8 +tomlkit==0.12.1 # via pylint twine==4.0.2 # via -r requirements/quality.in @@ -215,9 +215,10 @@ typing-extensions==4.7.1 # -r requirements/test.txt # asgiref # astroid + # edx-opaque-keys # pylint # rich -urllib3==2.0.3 +urllib3==2.0.4 # via # requests # twine diff --git a/requirements/test.txt b/requirements/test.txt index e30c5713..6089772e 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -10,11 +10,11 @@ asgiref==3.7.2 # django attrs==23.1.0 # via -r requirements/base.txt -click==8.1.5 +click==8.1.7 # via code-annotations -code-annotations==1.3.0 +code-annotations==1.5.0 # via -r requirements/test.in -coverage[toml]==7.2.7 +coverage[toml]==7.3.0 # via pytest-cov ddt==1.6.0 # via -r requirements/test.in @@ -22,11 +22,11 @@ django==3.2.20 # via # -c requirements/common_constraints.txt # -r requirements/base.txt -edx-opaque-keys[django]==2.3.0 +edx-opaque-keys[django]==2.5.0 # via -r requirements/base.txt -exceptiongroup==1.1.2 +exceptiongroup==1.1.3 # via pytest -fastavro==1.8.0 +fastavro==1.8.2 # via -r requirements/base.txt iniconfig==2.0.0 # via pytest @@ -40,7 +40,7 @@ pbr==5.11.1 # via # -r requirements/base.txt # stevedore -pluggy==1.2.0 +pluggy==1.3.0 # via pytest pymongo==3.13.0 # via @@ -60,7 +60,7 @@ pytz==2023.3 # via # -r requirements/base.txt # django -pyyaml==6.0 +pyyaml==6.0.1 # via code-annotations sqlparse==0.4.4 # via @@ -81,3 +81,4 @@ typing-extensions==4.7.1 # via # -r requirements/base.txt # asgiref + # edx-opaque-keys diff --git a/test_utils/test_settings.py b/test_utils/test_settings.py index 3701e3c0..a0fd9143 100644 --- a/test_utils/test_settings.py +++ b/test_utils/test_settings.py @@ -29,3 +29,29 @@ ) SECRET_KEY = "not-so-secret-key" +EVENT_BUS_PRODUCER_CONFIG = { + 'org.openedx.content_authoring.xblock.published.v1': ( + { + 'topic': 'content-authoring-xblock-lifecycle', + 'event_key_field': 'xblock_info.usage_key', + 'enabled': True + }, + { + 'topic': 'content-authoring-all-status', + 'event_key_field': 'xblock_info.usage_key', + 'enabled': True + }, + { + 'topic': 'content-authoring-xblock-published', + 'event_key_field': 'xblock_info.usage_key', + 'enabled': False + }, + ), + 'org.openedx.content_authoring.xblock.deleted.v1': ( + { + 'topic': 'content-authoring-xblock-lifecycle', + 'event_key_field': 'xblock_info.usage_key', + 'enabled': True + }, + ), +}