Skip to content

Commit

Permalink
test: bringing ModelPublisherTask usage closer to how it is used in r…
Browse files Browse the repository at this point in the history
…eal life
  • Loading branch information
rodrigoalmeidaee authored and joaodaher committed Apr 22, 2024
1 parent 69b9ee3 commit 1798fed
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 14 deletions.
1 change: 1 addition & 0 deletions sample_project/sample_app/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ class SampleAppConfig(AppConfig):

def ready(self):
from sample_project.sample_app import tasks # noqa: F401
from sample_project.sample_app import signals # noqa: F401
14 changes: 14 additions & 0 deletions sample_project/sample_app/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver

from sample_app import models, tasks


@receiver(post_save, sender=models.Person)
def publish_person(sender, instance: models.Person, **kwargs):
tasks.PublishPersonTask.sync(obj=instance, event="saved")


@receiver(post_delete, sender=models.Person)
def delete_person(sender, instance: models.Person, **kwargs):
tasks.PublishPersonTask.sync(obj=instance, event="deleted")
8 changes: 4 additions & 4 deletions sample_project/sample_app/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ def revert(cls, data: dict):

class PublishPersonTask(ModelPublisherTask):
@classmethod
def build_message_content(cls, obj: Model, **kwargs) -> dict:
return {"name": obj.name}
def build_message_content(cls, obj: Model, event: str, **kwargs) -> dict:
return {"id": obj.pk, "name": obj.name}

@classmethod
def build_message_attributes(cls, obj: Model, **kwargs) -> dict[str, str]:
return {"any-custom-attribute": "yay!"}
def build_message_attributes(cls, obj: Model, event: str, **kwargs) -> dict[str, str]:
return {"any-custom-attribute": "yay!", "event": event}


class DummyRoutineTask(RoutineTask):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,53 @@
from unittest.mock import patch, ANY

from django.test import TransactionTestCase
from gcp_pilot.mocker import patch_auth

from sample_app import models
import json


class PublisherTaskTest(TransactionTestCase):
def test_propagate_headerss(self):
def setUp(self):
super().setUp()
auth = patch_auth()
auth.start()
self.addCleanup(auth.stop)

def test_propagate_headers(self):
url = "/create-person"
data = {"name": "Harry Potter"}
headers = {
"traceparent": "trace-this-potato",
"another-random-header": "please-do-not-propagate-this",
}
django_headers = {f"HTTP_{key.upper()}": value for key, value in headers.items()}
with patch("django_cloud_tasks.tasks.publisher_task.CloudPublisher") as publisher:
self.client.post(path=url, data=data, content_type="application/json", **django_headers)
with patch("django_cloud_tasks.tasks.publisher_task.CloudPublisher.publish") as publish:
result = self.client.post(path=url, data=data, content_type="application/json", **django_headers)

self.assertEqual(201, result.status_code)
expected_message = json.dumps(
{"id": result.json()["pk"], "name": "Harry Potter", "_http_headers": {"Traceparent": "trace-this-potato"}}
)
expected_attributes = {"any-custom-attribute": "yay!", "event": "saved"}
publish.assert_called_once_with(message=expected_message, topic_id=ANY, attributes=expected_attributes)

def test_usage_inside_transaction(self):
with patch("django_cloud_tasks.tasks.publisher_task.CloudPublisher.publish"):
existing = models.Person.objects.create(name="Potter Harry")

url = "/replace-person"
data = {"name": "Harry Potter", "person_to_replace_id": existing.pk}
with patch("django_cloud_tasks.tasks.publisher_task.CloudPublisher.publish") as publish:
result = self.client.post(path=url, data=data, content_type="application/json")

self.assertEqual(201, result.status_code)
self.assertEqual(2, publish.call_count)

expected_message = json.dumps({"id": existing.pk, "name": "Potter Harry"})
expected_attributes = {"any-custom-attribute": "yay!", "event": "deleted"}
publish.assert_any_call(message=expected_message, topic_id=ANY, attributes=expected_attributes)

expected_message = '{"name": "Harry Potter", "_http_headers": {"Traceparent": "trace-this-potato"}}'
publisher_instance = publisher.return_value
publisher_instance.publish.assert_called_once_with(message=expected_message, topic_id=ANY, attributes=ANY)
expected_message = json.dumps({"id": result.json()["pk"], "name": "Harry Potter"})
expected_attributes = {"any-custom-attribute": "yay!", "event": "saved"}
publish.assert_any_call(message=expected_message, topic_id=ANY, attributes=expected_attributes)
22 changes: 18 additions & 4 deletions sample_project/sample_app/views.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
import json
from django.db import transaction

from django.http import JsonResponse
from django.views import View

from sample_app import models
from sample_app.tasks import PublishPersonTask


class PersonCreateView(View):
def post(self, request, *args, **kwargs):
person = models.Person.objects.create(**json.loads(request.body))
PublishPersonTask.sync(obj=person)
return JsonResponse(status=201, data={"status": "published"})
person = models.Person(**json.loads(request.body))
person.save()
return JsonResponse(status=201, data={"status": "published", "pk": person.pk})


class PersonReplaceView(View):
@transaction.atomic
def post(self, request, *args, **kwargs):
payload = json.loads(request.body)
person_to_replace_id = payload.pop("person_to_replace_id")

to_delete = models.Person.objects.get(pk=person_to_replace_id)
to_delete.delete()

person = models.Person(**payload)
person.save()
return JsonResponse(status=201, data={"status": "published", "pk": person.pk})
1 change: 1 addition & 0 deletions sample_project/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
urlpatterns = [
path("", include("django_cloud_tasks.urls")),
path("create-person", views.PersonCreateView.as_view()),
path("replace-person", views.PersonReplaceView.as_view()),
]

0 comments on commit 1798fed

Please sign in to comment.