Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions apps/sponsors/models/benefits.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Benefit feature and configuration models for the sponsors app."""

from django import forms
from django.db import models
from django.db import IntegrityError, models, transaction
from django.db.models import UniqueConstraint
from django.urls import reverse
from polymorphic.models import PolymorphicModel
Expand Down Expand Up @@ -155,11 +155,16 @@ def create_benefit_feature(self, sponsor_benefit, **kwargs):

asset_qs = content_object.assets.filter(internal_name=self.internal_name)
if not asset_qs.exists():
asset = self.ASSET_CLASS(
content_object=content_object,
internal_name=self.internal_name,
)
asset.save()
try:
with transaction.atomic():
asset = self.ASSET_CLASS(
content_object=content_object,
internal_name=self.internal_name,
)
asset.save()
except IntegrityError:
if not content_object.assets.filter(internal_name=self.internal_name).exists():
raise

return benefit_feature

Expand Down
24 changes: 24 additions & 0 deletions apps/sponsors/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,30 @@ def test_cant_create_same_asset_twice(self):
self.config.create_benefit_feature(self.sponsor_benefit)
self.assertEqual(1, TextAsset.objects.count())

def test_create_benefit_feature_with_preexisting_asset_no_crash(self):
"""Regression: submitting a new sponsorship when the sponsor already
has an asset with the same internal_name (from a prior application)
should not raise an IntegrityError."""
sponsor = self.sponsor_benefit.sponsorship.sponsor
TextAsset.objects.create(
content_object=sponsor,
internal_name=self.config.internal_name,
)
# should not raise IntegrityError
self.config.create_benefit_feature(self.sponsor_benefit)
self.assertEqual(1, TextAsset.objects.count())

def test_integrity_error_reraised_when_asset_missing(self):
"""An IntegrityError that is NOT a duplicate-asset collision must
propagate so it doesn't get silently swallowed."""
from unittest.mock import patch

with (
patch.object(TextAsset, "save", side_effect=IntegrityError("unrelated")),
self.assertRaises(IntegrityError),
):
self.config.create_benefit_feature(self.sponsor_benefit)

def test_clone_configuration_for_new_sponsorship_benefit_with_new_due_date(self):
sp_benefit = baker.make(SponsorshipBenefit, year=2023)

Expand Down
Loading