Skip to content

Commit

Permalink
refactor!: move load_all_events to more visible location (#187)
Browse files Browse the repository at this point in the history
Also adds a test
  • Loading branch information
Rebecca Graber authored Feb 27, 2023
1 parent 9837c52 commit 6f02fbc
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 35 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ Change Log
Unreleased
----------

[6.0.0] - 2023-02-23
---------------------
Changed
~~~~~~~
* **Breaking change**: Moved load_all_events() from openedx_events.tests.utils to openedx_events.tooling

[5.1.0] - 2023-02-07
---------------------
Added
Expand Down
2 changes: 1 addition & 1 deletion openedx_events/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
more information about the project.
"""

__version__ = "5.1.0"
__version__ = "6.0.0"
4 changes: 2 additions & 2 deletions openedx_events/event_bus/avro/tests/test_avro.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
deserialize_bytes_to_event_data,
serialize_event_data_to_bytes,
)
from openedx_events.tests.utils import FreezeSignalCacheMixin, load_all_signals
from openedx_events.tooling import OpenEdxPublicSignal
from openedx_events.tests.utils import FreezeSignalCacheMixin
from openedx_events.tooling import OpenEdxPublicSignal, load_all_signals

# If a signal is explicitly not for use with the event bus, add it to this list
# and document why in the event's annotations
Expand Down
53 changes: 52 additions & 1 deletion openedx_events/tests/test_tooling.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
EventsToolingTest: Test events tooling.
"""
import datetime
import sys
from contextlib import contextmanager
from unittest.mock import Mock, patch
from uuid import UUID, uuid1
Expand All @@ -17,7 +18,7 @@
from openedx_events.data import EventsMetadata
from openedx_events.exceptions import SenderValidationError
from openedx_events.tests.utils import FreezeSignalCacheMixin
from openedx_events.tooling import OpenEdxPublicSignal
from openedx_events.tooling import OpenEdxPublicSignal, _process_all_signals_modules, load_all_signals


@contextmanager
Expand Down Expand Up @@ -326,3 +327,53 @@ def test_send_event_disabled(self, send_mock):

send_mock.assert_not_called()
self.assertListEqual([], result)


class TestLoadAllSignals(FreezeSignalCacheMixin, TestCase):
""" Tests for the load_all_signals method"""
def setUp(self):
# load_all_signals does spooky things with module loading,
# so save the current state of any loaded signals modules to avoid disrupting other tests
super().setUp()
self.old_signal_modules = {}

def save_module(module_name):
if module_name in sys.modules:
self.old_signal_modules[module_name] = sys.modules[module_name]
_process_all_signals_modules(save_module)

def tearDown(self):
for k, v in self.old_signal_modules.items():
sys.modules[k] = v
super().tearDown()

def test_load_all_signals(self):
"""
Tests load_all_signals loads all the signals in the entire library
It's not the most robust since it just tests a few arbitrary signals but actually testing all the signals
would require updating this test every time a new signal is added
"""

# remove any existing imports of signals modules
for k in self.old_signal_modules:
sys.modules.pop(k)

# this class uses FreezeSignalCacheMixin so we can safely remove everything from the OpenEdxPublicSignal
# cache and it shouldn't affect any other tests
OpenEdxPublicSignal._mapping = {} # pylint: disable=protected-access
OpenEdxPublicSignal.instances = []
with pytest.raises(KeyError):
OpenEdxPublicSignal.get_signal_by_type('org.openedx.content_authoring.course.catalog_info.changed.v1')
with pytest.raises(KeyError):
OpenEdxPublicSignal.get_signal_by_type('org.openedx.learning.course.enrollment.created.v1')

load_all_signals()
assert isinstance(
OpenEdxPublicSignal.get_signal_by_type('org.openedx.content_authoring.course.catalog_info.changed.v1'),
OpenEdxPublicSignal
)
assert isinstance(
OpenEdxPublicSignal.get_signal_by_type('org.openedx.learning.course.enrollment.created.v1'),
OpenEdxPublicSignal
)
31 changes: 0 additions & 31 deletions openedx_events/tests/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"""
Utils used by Open edX event tests.
"""
import pkgutil
from importlib import import_module

from openedx_events.tooling import OpenEdxPublicSignal

Expand Down Expand Up @@ -127,32 +125,3 @@ def start_events_isolation(cls):
cls().disable_all_events()
cls().enable_events_by_type(*cls.ENABLED_OPENEDX_EVENTS)
cls().allow_send_events_failure(*cls.ENABLED_OPENEDX_EVENTS)


def load_all_signals():
"""
Ensure OpenEdxPublicSignal.all_events() cache is fully populated.
Loads all non-test signals.py modules.
"""
found = set()

root = import_module('openedx_events')
for m in pkgutil.walk_packages(root.__path__, root.__name__ + '.'):
module_name = m.name
if 'tests' in module_name.split('.') or '.test_' in module_name:
continue
if module_name.endswith('.signals'):
import_module(module_name)
found.add(module_name)

# Check that the auto-discovered list matches the known modules.
# This is just here to ensure that the auto-discovery is working
# properly and doesn't start to silently fail.
#
# If this assertion fails because a module has been added, renamed,
# or deleted, please update the hardcoded list.
assert found == {
'openedx_events.content_authoring.signals',
'openedx_events.learning.signals',
}
27 changes: 27 additions & 0 deletions openedx_events/tooling.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"""
Tooling necessary to use Open edX events.
"""
import pkgutil
import warnings
from importlib import import_module
from logging import getLogger

from django.conf import settings
Expand Down Expand Up @@ -252,3 +254,28 @@ def allow_send_event_failure(self):
More information on send_robust in the Django official documentation.
"""
self._allow_send_event_failure = True


def _process_all_signals_modules(func):
"""
Walk the package tree and apply func on all signals.py files.
Arguments:
func: A method that takes a module name as its parameter
"""
root = import_module('openedx_events')
for m in pkgutil.walk_packages(root.__path__, root.__name__ + '.'):
module_name = m.name
if 'tests' in module_name.split('.') or '.test_' in module_name:
continue
if module_name.endswith('.signals'):
func(module_name)


def load_all_signals():
"""
Ensure OpenEdxPublicSignal.all_events() cache is fully populated.
Loads all non-test signals.py modules.
"""
_process_all_signals_modules(import_module)

0 comments on commit 6f02fbc

Please sign in to comment.