Skip to content

Commit

Permalink
add DonationBid to v2, under donations/bids (#738)
Browse files Browse the repository at this point in the history
[#184870652]
  • Loading branch information
uraniumanchor authored Nov 12, 2024
1 parent fda6c87 commit ec815e6
Show file tree
Hide file tree
Showing 9 changed files with 422 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ repos:
rev: 7.1.0
hooks:
- id: flake8
- repo: https://github.com/pycqa/autoflake
rev: v2.3.1
hooks:
- id: autoflake
args: [--remove-all-unused-imports, --in-place]
- repo: local
hooks:
- id: prettier
Expand Down
257 changes: 257 additions & 0 deletions tests/apiv2/test_donation_bids.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
from decimal import Decimal

from tests import randgen
from tests.util import APITestCase
from tracker import models
from tracker.api.serializers import DonationBidSerializer


class TestDonationBids(APITestCase):
model_name = 'donationbid'
serializer_class = DonationBidSerializer
extra_serializer_kwargs = {'with_permissions': 'tracker.view_hidden_bid'}
view_user_permissions = ['view_bid']

def _format_donation_bid(self, bid):
bid.refresh_from_db()
return {
'type': 'donationbid',
'id': bid.id,
'donation': bid.donation_id,
'bid': bid.bid_id,
'bid_name': bid.bid.fullname(),
'bid_state': bid.bid.state,
'amount': str(bid.amount),
}

def setUp(self):
super().setUp()
self.donor = randgen.generate_donor(self.rand)
self.donor.save()
self.donation = randgen.generate_donation(
self.rand, min_amount=10, max_amount=25
)
self.donation.save()
self.other_donation = randgen.generate_donation(self.rand)
self.other_donation.save()
self.pending_donation = randgen.generate_donation(
self.rand, domain='PAYPAL', transactionstate='PENDING'
)
self.pending_donation.save()
self.opened_bid = randgen.generate_bid(
self.rand,
event=self.event,
state='OPENED',
allow_children=True,
allowuseroptions=True,
)[0]
self.opened_bid.save()
self.opened_child = randgen.generate_bid(
self.rand, parent=self.opened_bid, state='OPENED', allow_children=False
)[0]
self.opened_child.save()
self.denied_child = randgen.generate_bid(
self.rand, parent=self.opened_bid, state='DENIED', allow_children=False
)[0]
self.denied_child.save()
self.opened_child_bid = models.DonationBid.objects.create(
donation=self.donation,
bid=self.opened_child,
amount=Decimal(self.rand.uniform(5.0, 9.5)),
)
self.denied_child_bid = models.DonationBid.objects.create(
donation=self.donation,
bid=self.denied_child,
amount=self.donation.amount - self.opened_child_bid.amount,
)
self.other_child_bid = models.DonationBid.objects.create(
donation=self.other_donation,
bid=self.opened_child,
amount=self.other_donation.amount / 3,
)
self.hidden_bid, hidden_children = randgen.generate_bid(
self.rand,
event=self.event,
min_children=1,
max_children=1,
state='HIDDEN',
allow_children=True,
allowuseroptions=True,
)
self.hidden_child = hidden_children[0][0]
self.hidden_bid.save()
self.hidden_child.save()
self.hidden_denied_child = randgen.generate_bid(
self.rand, parent=self.hidden_bid, state='DENIED', allow_children=False
)[0]
self.hidden_denied_child.save()
self.hidden_child_bid = models.DonationBid.objects.create(
donation=self.other_donation,
bid=self.hidden_child,
amount=self.other_donation.amount / 3,
)
self.hidden_denied_child_bid = models.DonationBid.objects.create(
donation=self.other_donation,
bid=self.hidden_denied_child,
amount=self.other_donation.amount / 3,
)
self.pending_donation_bid = models.DonationBid.objects.create(
donation=self.pending_donation,
bid=self.opened_child,
amount=self.pending_donation.amount,
)

def test_fetch(self):
with self.saveSnapshot():
with self.subTest('via donation'):
data = self.get_noun(
'bids', self.donation, model_name='donations', user=self.view_user
)
self.assertExactV2Models([self.opened_child_bid], data['results'])

data = self.get_noun(
'bids',
self.donation,
data={'all': ''},
model_name='donations',
user=self.view_user,
)
self.assertExactV2Models(
[self.opened_child_bid, self.denied_child_bid], data['results']
)

data = self.get_noun(
'bids',
self.other_donation,
data={'all': ''},
model_name='donations',
user=self.view_user,
)
self.assertExactV2Models(
[
self.other_child_bid,
self.hidden_child_bid,
self.hidden_denied_child_bid,
],
data['results'],
)

with self.subTest('via parent bid'):
data = self.get_noun(
'donations',
self.opened_bid,
model_name='bid',
user=self.view_user,
)
self.assertExactV2Models(
[self.opened_child_bid, self.other_child_bid], data['results']
)

data = self.get_noun(
'donations',
self.opened_bid,
data={'all': ''},
model_name='bid',
user=self.view_user,
)
self.assertExactV2Models(
[
self.opened_child_bid,
self.denied_child_bid,
self.other_child_bid,
],
data['results'],
)

data = self.get_noun(
'donations',
self.hidden_bid,
model_name='bid',
user=self.view_user,
)
self.assertExactV2Models(
[self.hidden_child_bid, self.hidden_denied_child_bid],
data['results'],
)

with self.subTest('via child bid'):
data = self.get_noun(
'donations',
self.opened_child,
model_name='bid',
user=self.view_user,
)
self.assertExactV2Models(
[self.opened_child_bid, self.other_child_bid], data['results']
)

data = self.get_noun(
'donations',
self.denied_child,
model_name='bid',
user=self.view_user,
)
self.assertExactV2Models([self.denied_child_bid], data['results'])

data = self.get_noun(
'donations',
self.hidden_child,
model_name='bid',
user=self.view_user,
)
self.assertExactV2Models([self.hidden_child_bid], data['results'])

with self.subTest('error cases'):
# strictly speaking, 403, but easier to write the permission check this way
self.get_noun(
'bids',
self.donation,
data={'all': ''},
model_name='donations',
user=None,
status_code=404,
)
self.get_noun(
'bids',
self.pending_donation,
model_name='donations',
user=None,
status_code=404,
)
self.get_noun(
'donations',
self.opened_bid,
data={'all': ''},
model_name='bid',
user=None,
status_code=404,
)
self.get_noun(
'donations',
self.denied_child,
model_name='bid',
user=None,
status_code=404,
)
self.get_noun(
'donations',
self.hidden_bid,
model_name='bid',
user=None,
status_code=404,
)

def test_serializer(self):
with self.assertRaises(AssertionError):
print(DonationBidSerializer(self.hidden_child_bid).data)

data = DonationBidSerializer(
self.hidden_child_bid, with_permissions=('tracker.view_hidden_bid')
).data
self.assertEqual(data, self._format_donation_bid(self.hidden_child_bid))

data = DonationBidSerializer(
[self.opened_child_bid, self.other_child_bid], many=True
).data
self.assertEqual(data[0], self._format_donation_bid(self.opened_child_bid))
self.assertEqual(data[1], self._format_donation_bid(self.other_child_bid))
7 changes: 5 additions & 2 deletions tests/randgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ def generate_bid(
rand,
*,
allow_children=None,
allowuseroptions=None,
min_children=2,
max_children=5,
max_depth=2,
Expand All @@ -299,6 +300,8 @@ def generate_bid(
bid = Bid()
bid.description = random_bid_description(rand, bid.name)
assert run or event or parent, 'Need at least one of run, event, or parent'
if allowuseroptions is not None:
bid.allowuseroptions = allowuseroptions
if parent:
bid.parent = parent
bid.speedrun = parent.speedrun
Expand Down Expand Up @@ -411,12 +414,12 @@ def generate_donation(
), 'Local donations must be specified as COMPLETED'

if not no_donor:
if not donor:
if donor is None:
if donors:
donor = rand.choice(donors)
else:
assert Donor.objects.exists(), 'No donor provided and none exist'
donor = rand.choice(Donor.objects.all())
assert donor, 'No donor provided and none exist'
donation.donor = donor
donation.clean()
return donation
Expand Down
56 changes: 50 additions & 6 deletions tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ class APITestCase(TransactionTestCase, AssertionHelpers):
fixtures = ['countries']
model_name = None
serializer_class = None
extra_serializer_kwargs = {}
format_model = None
view_user_permissions = [] # trickles to add_user and locked_user
add_user_permissions = [] # trickles to locked_user
Expand Down Expand Up @@ -705,7 +706,8 @@ def assertV2ModelPresent(
), 'no serializer_class provided and raw model was passed'
expected_model.refresh_from_db()
expected_model = self.serializer_class(
expected_model, **serializer_kwargs or {}
expected_model,
**{**(serializer_kwargs or {}), **self.extra_serializer_kwargs},
).data
# FIXME: gross hack
from tracker.api.serializers import EventNestedSerializerMixin
Expand All @@ -717,8 +719,8 @@ def assertV2ModelPresent(
(
m
for m in data
if expected_model['type'] == m['type']
and expected_model['id'] == m['id']
if expected_model['type'] == m.get('type', None)
and expected_model['id'] == m.get('id', None)
),
None,
)
Expand Down Expand Up @@ -748,15 +750,17 @@ def assertV2ModelNotPresent(self, unexpected_model, data):
assert hasattr(
self, 'serializer_class'
), 'no serializer_class provided and raw model was passed'
unexpected_model = self.serializer_class(unexpected_model).data
unexpected_model = self.serializer_class(
unexpected_model, **self.extra_serializer_kwargs
).data
if (
next(
(
model
for model in data
if (
model['id'] == unexpected_model['id']
and model['type'] == unexpected_model['type']
model.get('id', None) == unexpected_model['id']
and model.get('type', None) == unexpected_model['type']
)
),
None,
Expand All @@ -768,6 +772,46 @@ def assertV2ModelNotPresent(self, unexpected_model, data):
% (unexpected_model['type'], unexpected_model['id'])
)

def assertExactV2Models(
self,
expected_models,
unexpected_models,
data=None,
*,
exact_count=True,
msg=None,
**kwargs,
):
"""similar to V2ModelPresent, but allows you to explicitly check that certain models are not present
by default it also asserts exact count, but you can turn that off if you want
"""
problems = []
if data is None:
data = unexpected_models
unexpected_models = []
if exact_count and len(data) != len(expected_models):
problems.append(
f'Data length mismatch, expected {len(expected_models)}, got {len(data)}'
)
for m in expected_models:
try:
self.assertV2ModelPresent(m, data, **kwargs)
except AssertionError as e:
problems.append(str(e))
for m in unexpected_models:
try:
self.assertV2ModelNotPresent(m, data)
except AssertionError as e:
problems.append(str(e))
if problems:
parts = []
if msg:
parts.append(msg)
parts.append(f'Had {len(problems)} problem(s) asserting model data:')
parts.extend(problems)

self.fail('\n'.join(parts))

def assertLogEntry(self, model_name: str, pk: int, change_type, message: str):
from django.contrib.admin.models import LogEntry

Expand Down
Loading

0 comments on commit ec815e6

Please sign in to comment.