Skip to content

Commit

Permalink
feat: Refactor notification system test suite to use synchronous exec…
Browse files Browse the repository at this point in the history
…ution, enabling deterministic testing of async flows while maintaining async processing in production. Add comprehensive test coverage for notification creation, template rendering, and error handling with proper event logging.
  • Loading branch information
adrianmcphee committed Nov 25, 2024
1 parent d755fdd commit 645afe2
Show file tree
Hide file tree
Showing 25 changed files with 956 additions and 293 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


def forward_func(apps, schema_editor):
Bounty = apps.capabilities.get_model("product_management.Bounty")
Bounty = apps.get_model("product_management", "Bounty")
for bounty in Bounty.objects.all():
expertise_as_str = ", ".join([exp.name.title() for exp in bounty.expertise.all()])
skill_name = ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


def forward_func(apps, schema_editor):
Bounty = apps.capabilities.get_model("product_management", "Bounty")
Bounty = apps.get_model("product_management", "Bounty")

for bounty in Bounty.objects.all():
status = int(bounty.status)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


def forward_func(apps, schema_editor):
Challenge = apps.capabilities.get_model("product_management", "Challenge")
Challenge = apps.get_model("product_management", "Challenge")

for challenge in Challenge.objects.all():
status = int(challenge.status)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


def forward_func(apps, schema_editor):
Initiative = apps.capabilities.get_model("product_management", "Initiative")
Initiative = apps.get_model("product_management", "Initiative")
for initiative in Initiative.objects.all():
status = int(initiative.status)
if status == 1:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@


def forward_fun(apps, schema_editor):
Challenge = apps.capabilities.get_model("product_management.Challenge")
Challenge = apps.get_model("product_management", "Challenge")
for challenge in Challenge.objects.all():
if challenge.priority in [0, "0"]:
challenge.priority = HIGH
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ def convert_generic_to_explicit(apps, schema_editor):
Person = apps.get_model('talent', 'Person')
ContentType = apps.get_model('contenttypes', 'ContentType')

# Get content types using the historical models
org_content_type = ContentType.objects.get(
# Create both ContentTypes if they don't exist
org_content_type, _ = ContentType.objects.get_or_create(
app_label='commerce',
model='organisation'
)
person_content_type = ContentType.objects.get(

person_content_type, _ = ContentType.objects.get_or_create(
app_label='talent',
model='person'
)
Expand All @@ -33,7 +34,6 @@ def convert_generic_to_explicit(apps, schema_editor):
product.save()

def reverse_convert(apps, schema_editor):
# If you need to reverse the migration
pass

class Migration(migrations.Migration):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@


def forward_func(apps, schema_editor):
apps.capabilities.get_model("talent.PersonSkill").objects.all().delete()
PersonSkill = apps.get_model("talent", "PersonSkill")
PersonSkill.objects.all().delete()


def reverse_func(apps, schema_editor):
pass


class Migration(migrations.Migration):
Expand All @@ -14,7 +19,7 @@ class Migration(migrations.Migration):
]

operations = [
migrations.RunPython(forward_func, migrations.RunPython.noop),
migrations.RunPython(forward_func, reverse_func),
migrations.RemoveField(
model_name="personskill",
name="expertise",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


def forward_func(apps, schema_editor):
BountyDeliveryAttempt = apps.capabilities.get_model("talent.BountyDeliveryAttempt")
BountyDeliveryAttempt = apps.get_model("talent", "BountyDeliveryAttempt")
for attempt in BountyDeliveryAttempt.objects.all():
if attempt.kind in ["0", 0]:
attempt.kind = NEW
Expand All @@ -19,6 +19,10 @@ def forward_func(apps, schema_editor):
attempt.save()


def reverse_func(apps, schema_editor):
pass


class Migration(migrations.Migration):

dependencies = [
Expand All @@ -33,5 +37,5 @@ class Migration(migrations.Migration):
choices=[("New", "New"), ("Approved", "Approved"), ("Rejected", "Rejected")], default="New"
),
),
migrations.RunPython(forward_func, migrations.RunPython.noop),
migrations.RunPython(forward_func, reverse_func),
]
18 changes: 8 additions & 10 deletions apps/common/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,15 +425,13 @@ class Media:

# Django Q Configuration (using PostgreSQL as broker)
Q_CLUSTER = {
'name': 'OpenUnited',
'name': 'DjangoORM',
'workers': int(os.getenv('DJANGO_Q_WORKERS', '4')),
'recycle': 500,
'timeout': 300,
'retry': 600,
'compress': True,
'save_limit': 250,
'queue_limit': 500,
'cpu_affinity': 1,
'label': 'Django Q',
'orm': 'default'
'timeout': 90,
'retry': 120,
'queue_limit': 50,
'bulk': 10,
'orm': 'default',
'sync': False,
'queue_table': 'django_q_task'
}
56 changes: 45 additions & 11 deletions apps/common/settings/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,76 @@
'PASSWORD': 'postgres',
'HOST': 'localhost',
'PORT': '5432',
'ATOMIC_REQUESTS': False,
'TEST': {
'NAME': 'test_db',
},
}
}

PASSWORD_HASHERS = [
'django.contrib.auth.hashers.MD5PasswordHasher',
]

# Disable migrations
# Disable migrations except for django_q
class DisableMigrations:
def __contains__(self, item):
return True
return item != 'django_q' # Allow django_q migrations

def __getitem__(self, item):
return None
if item == 'django_q':
return None # Use normal migrations for django_q
return 'notmigrations' # Disable migrations for other apps

MIGRATION_MODULES = DisableMigrations()

SECRET_KEY = 'django-insecure-test-key-123' # Only for testing

# Configure Django-Q for testing
# Configure Django-Q for testing async behavior
Q_CLUSTER = {
'name': 'OpenUnited_Test',
'workers': 2,
'name': 'TestCluster',
'workers': 1,
'timeout': 30,
'retry': 60,
'sync': False,
'poll': 100,
'queue_limit': 50,
'bulk': 1,
'orm': 'default',
'sync': True,
'catch_up': False,
'bulk': 1
'log_level': 'DEBUG',
}

# Use synchronous event bus in tests
EVENT_BUS = {
'BACKEND': 'apps.event_hub.services.backends.django_q.DjangoQBackend',
'LOGGING_ENABLED': True,
'TASK_TIMEOUT': 30,
'SYNC_IN_TEST': True, # Add this flag
'SYNC_IN_TEST': False,
}

# Add detailed logging configuration
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
},
},
'loggers': {
'django_q': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': True,
},
'apps': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': True,
},
},
}
3 changes: 2 additions & 1 deletion apps/engagement/apps.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.apps import AppConfig
from apps.event_hub.events import EventTypes


class EngagementConfig(AppConfig):
Expand All @@ -10,4 +11,4 @@ def ready(self):
from .events import handle_product_created

event_bus = get_event_bus()
event_bus.register_listener('product.created', handle_product_created)
event_bus.register_listener(EventTypes.PRODUCT_CREATED, handle_product_created)
Loading

0 comments on commit 645afe2

Please sign in to comment.