Skip to content

Commit

Permalink
support Run editing on V2 (#719)
Browse files Browse the repository at this point in the history
[#184870726]
  • Loading branch information
uraniumanchor authored Oct 3, 2024
1 parent f825d92 commit 1811d91
Show file tree
Hide file tree
Showing 24 changed files with 1,078 additions and 238 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ tracker/templates/ui/generated/
geckodriver.log
test-results
tests/_trial_temp
tests/media
tests/snapshots

# Yarn files for projects not using zero-installs,
# taken from https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored.
Expand Down
1 change: 0 additions & 1 deletion tests/.gitignore

This file was deleted.

8 changes: 0 additions & 8 deletions tests/apiv2/test_bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,11 +504,3 @@ def test_single(self):
self.assertV2ModelPresent(
self._format_bid(self.opened_bid), serialized.data
)

with self.subTest('nested in event'):
serialized = BidSerializer(
self.opened_bid, event_pk=self.event.id, tree=True
)
self.assertV2ModelPresent(
self._format_bid(self.opened_bid, with_event=False), serialized.data
)
2 changes: 1 addition & 1 deletion tests/apiv2/test_milestone.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def test_patch(self):
MilestoneSerializer(self.public_milestone).data, data
)
self.patch_detail(
self.public_milestone, data={'event': self.event}, status_code=400
self.public_milestone, data={'event': self.event.id}, status_code=400
)
self.patch_detail(
self.hidden_milestone, data={'amount': 1250}, status_code=403
Expand Down
1 change: 1 addition & 0 deletions tests/apiv2/test_runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class TestRunners(APITestCase):
serializer_class = RunnerSerializer

def setUp(self):
super().setUp()
self.rand = random.Random()
self.event = randgen.generate_event(self.rand)
self.event.save()
Expand Down
261 changes: 258 additions & 3 deletions tests/apiv2/test_runs.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@

class TestRunViewSet(TestSpeedRunBase, APITestCase):
model_name = 'speedrun'
serializer_class = SpeedRunSerializer
view_user_permissions = ['can_view_tech_notes']

def setUp(self):
super().setUp()
self.client.force_authenticate(user=self.locked_user)

def test_detail(self):
with self.subTest('normal detail'):
with self.subTest('normal detail'), self.saveSnapshot():
serialized = SpeedRunSerializer(self.run1)
data = self.get_detail(self.run1)
self.assertEqual(serialized.data, data)
Expand All @@ -39,7 +40,7 @@ def test_detail(self):
)

def test_list(self):
with self.subTest('normal lists'):
with self.subTest('normal lists'), self.saveSnapshot():
serialized = SpeedRunSerializer(
models.SpeedRun.objects.filter(event=self.event), many=True
)
Expand All @@ -54,7 +55,7 @@ def test_list(self):
data = self.get_list(kwargs={'event_pk': self.event.pk})
self.assertEqual(data['results'], serialized.data)

with self.subTest('requesting tech notes'):
with self.subTest('requesting tech notes'), self.saveSnapshot():
serialized = SpeedRunSerializer(
models.SpeedRun.objects.filter(event=self.event),
with_permissions=('tracker.can_view_tech_notes',),
Expand All @@ -70,6 +71,260 @@ def test_list(self):
with self.subTest('not a real event'):
self.get_list(kwargs={'event_pk': self.event.pk + 100}, status_code=404)

def test_create(self):
with self.subTest('smoke test'), self.saveSnapshot(), self.assertLogsChanges(1):
data = self.post_new(
data={
'event': self.event.pk,
'name': 'New Run',
'category': 'any%',
'runners': [self.runner1.pk],
'run_time': '15:00',
'setup_time': '5:00',
}
)
model = models.SpeedRun.objects.get(id=data['id'])
self.assertV2ModelPresent(model, data)

with self.subTest(
'full blown model w/implicit tag creation'
), self.saveSnapshot(), self.assertLogsChanges(1):
last_run = models.SpeedRun.objects.filter(event=self.event).last()
data = self.post_new(
data={
'event': self.event.short,
'name': 'Mega Man Overclocked',
'display_name': 'Mega Man Overclocked',
'twitch_name': 'Mega Man',
'description': 'This run will be amazing.',
'category': 'any%',
'coop': True,
'onsite': 'ONSITE',
'console': 'NES',
'release_year': 1988,
'runners': [self.runner1.name],
'hosts': [self.headset1.name],
'commentators': [self.headset2.name],
'order': 'last',
'run_time': '15:00',
'setup_time': '5:00',
'anchor_time': last_run.endtime,
'tech_notes': 'This run has two players.',
'video_links': [
{'link_type': 'youtube', 'url': 'https://youtu.be/deadbeef2'}
],
'priority_tag': 'coop',
'tags': ['bonus'],
}
)
model = models.SpeedRun.objects.get(id=data['id'])
self.assertV2ModelPresent(
model,
data,
serializer_kwargs={
'with_tech_notes': True,
'with_permissions': ('tracker.can_view_tech_notes',),
},
)
self.assertEqual(
model.order, last_run.order + 1, msg='`last` order was incorrect'
)
self.assertEqual(
model.tech_notes,
'This run has two players.',
msg='`tech_notes` not accepted.',
)
self.assertQuerySetEqual(
models.Runner.objects.filter(id=self.runner1.id),
model.runners.all(),
msg='Runners were not assigned correctly',
)
self.assertQuerySetEqual(
models.Headset.objects.filter(id=self.headset1.id),
model.hosts.all(),
msg='Hosts were not assigned correctly',
)
self.assertQuerySetEqual(
models.Headset.objects.filter(id=self.headset2.id),
model.commentators.all(),
msg='Commentators were not assigned correctly',
)
link = models.VideoLink.objects.get(id=data['video_links'][0]['id'])
self.assertEqual(link.url, 'https://youtu.be/deadbeef2')
self.assertEqual(
model.priority_tag, models.Tag.objects.get_by_natural_key('coop')
)
self.assertEqual(
list(model.tags.all()), [models.Tag.objects.get_by_natural_key('bonus')]
)

with self.subTest('invalid PKs'), self.assertLogsChanges(0):
self.post_new(
data={
'event': 500,
'runners': [self.runner1.pk, 500],
},
status_code=400,
expected_error_codes={'event': 'invalid_pk', 'runners': 'invalid_pk'},
)

with self.subTest('invalid NKs'), self.assertLogsChanges(0):
self.post_new(
data={
'runners': [self.runner1.name, 'JesseDoe'],
'hosts': [self.headset1.name, 'JohnDoe'],
'commentators': [self.headset2.name, 'JaneDoe'],
'video_links': [{'link_type': 'google_video'}],
'priority_tag': 'invalid tag', # implicit creation, but fails validation
},
status_code=400,
expected_error_codes={
'runners': 'invalid_natural_key',
'hosts': 'invalid_natural_key',
'commentators': 'invalid_natural_key',
'video_links': {'link_type': 'invalid_natural_key'},
'priority_tag': 'invalid',
},
)

with self.subTest('blank entry smoke test'), self.assertLogsChanges(0):
self.post_new(
data={},
status_code=400,
expected_error_codes={
'event': 'required',
},
)

with self.subTest(
'event route smoke test'
), self.saveSnapshot(), self.assertLogsChanges(1):
data = self.post_new(
data={
'name': 'Extra Mario Bros',
'category': 'any%',
'run_time': '15:00',
'setup_time': '5:00',
'runners': [self.runner1.id],
},
kwargs={'event_pk': self.event1.pk},
)
model = models.SpeedRun.objects.get(id=data['id'])
self.assertV2ModelPresent(model, data)

with self.subTest('permissions smoke tests'):
self.post_new(data={}, status_code=403, user=None)
self.post_new(data={}, status_code=403, user=self.view_user)
self.post_new(
data={'event': self.locked_event.pk},
status_code=403,
user=self.add_user,
)

def test_update(self):
with self.subTest('smoke test'), self.saveSnapshot(), self.assertLogsChanges(1):
data = self.patch_detail(self.run1, data={'name': 'Changed Name'})
self.assertV2ModelPresent(self.run1, data)

with self.subTest(
'update with PKs'
), self.saveSnapshot(), self.assertLogsChanges(1):
data = self.patch_detail(
self.run1,
data={
'runners': [self.runner1.id],
'hosts': [self.headset2.id],
'commentators': [self.headset1.id],
},
)
self.assertV2ModelPresent(self.run1, data)
self.assertQuerySetEqual(
models.Runner.objects.filter(id=self.runner1.id),
self.run1.runners.all(),
)
self.assertQuerySetEqual(
models.Headset.objects.filter(id=self.headset2.id),
self.run1.hosts.all(),
)
self.assertQuerySetEqual(
models.Headset.objects.filter(id=self.headset1.id),
self.run1.commentators.all(),
)

with self.subTest(
'update with NKs'
), self.saveSnapshot(), self.assertLogsChanges(1):
data = self.patch_detail(
self.run1,
data={
'runners': [self.runner2.name],
'hosts': [self.headset1.name],
'commentators': [self.headset2.name],
},
)
self.assertV2ModelPresent(self.run1, data)
self.assertQuerySetEqual(
models.Runner.objects.filter(id=self.runner2.id),
self.run1.runners.all(),
)
self.assertQuerySetEqual(
models.Headset.objects.filter(id=self.headset1.id),
self.run1.hosts.all(),
)
self.assertQuerySetEqual(
models.Headset.objects.filter(id=self.headset2.id),
self.run1.commentators.all(),
)

with self.subTest(
'update with existing tag'
), self.saveSnapshot(), self.assertLogsChanges(1):
data = self.patch_detail(self.run1, data={'tags': [self.tag1.name]})
self.assertV2ModelPresent(self.run1, data)
self.assertSetEqual(
{self.tag1.name}, {t.name for t in self.run1.tags.all()}
)

with self.subTest('update with new tag'), self.assertLogsChanges(1):
data = self.patch_detail(self.run1, data={'tags': ['brand_new']})
self.assertV2ModelPresent(self.run1, data)
self.assertSetEqual({'brand_new'}, {t.name for t in self.run1.tags.all()})

with self.subTest(
'clear everything out'
), self.saveSnapshot(), self.assertLogsChanges(1):
data = self.patch_detail(
self.run1,
data={
'hosts': [],
'commentators': [],
'priority_tag': None,
'tags': [],
},
)
self.assertV2ModelPresent(self.run1, data)
self.assertSequenceEqual([], self.run1.hosts.all())
self.assertSequenceEqual([], self.run1.commentators.all())
self.assertSequenceEqual([], self.run1.tags.all())

with self.subTest('no nested updates'), self.assertLogsChanges(0):
self.patch_detail(
self.run1,
data={'video_links': []},
status_code=400,
expected_error_codes={'video_links': 'no_nested_updates'},
)

with self.subTest('permissions smoke tests'):
self.patch_detail(self.run1, data={}, status_code=403, user=None)
self.patch_detail(self.run1, data={}, status_code=403, user=self.view_user)
self.patch_detail(
self.run1,
data={'event': self.locked_event.pk},
status_code=403,
user=self.add_user,
)


class TestRunSerializer(TestSpeedRunBase, APITestCase):
def _format_run(self, run, *, with_event=True, with_tech_notes=False):
Expand Down
1 change: 1 addition & 0 deletions tests/randgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,7 @@ def generate_milestone(
max_amount = event.targetamount
if amount is None:
amount = random_amount(rand, min_amount=min_amount, max_amount=max_amount)
# TODO: this very occasionally makes a duplicate
milestone = Milestone(
event=event,
amount=amount,
Expand Down
2 changes: 1 addition & 1 deletion tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def test_add_with_bad_field(self):
def test_search_with_offset_and_limit(self):
event = randgen.generate_event(self.rand, today_noon)
event.save()
randgen.generate_runs(self.rand, event, 5)
randgen.generate_runs(self.rand, event, 5, ordered=True)
randgen.generate_donors(self.rand, 25)
randgen.generate_donations(self.rand, event, 50, transactionstate='COMPLETED')
request = self.factory.get(
Expand Down
21 changes: 16 additions & 5 deletions tests/test_speedrun.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@ def setUp(self):
self.run4 = models.SpeedRun.objects.create(
name='Test Run 4', run_time='1:20:00', setup_time='5:00', order=None
)
self.run5 = models.SpeedRun.objects.create(name='Test Run 5', order=4)
self.run5 = models.SpeedRun.objects.create(
name='Test Run 5', order=4, run_time='15:00'
)
self.runner1 = models.Runner.objects.create(name='trihex')
self.runner2 = models.Runner.objects.create(name='neskamikaze')
self.headset1 = models.Headset.objects.create(name='SpikeVegeta')
self.headset2 = models.Headset.objects.create(name='puwexil')
link_type = models.VideoLinkType.objects.create(name='youtube')
self.video_link1 = models.VideoLink.objects.create(
run=self.run2, link_type=link_type, url='https://youtu.be/deadbeef'
Expand Down Expand Up @@ -77,11 +81,18 @@ def test_null_order(self):
self.assertEqual(self.run4.starttime, None)
self.assertEqual(self.run4.endtime, None)

def test_no_run_or_setup_time_run_start_time(self):
self.assertEqual(self.run5.starttime, None)
def test_ordered_needs_run_or_setup_time(self):
with self.assertRaises(ValidationError):
self.run5.run_time = '0'
self.run5.setup_time = '0'
self.run5.full_clean()

self.run5.setup_time = '5:00'
self.run5.full_clean()

def test_no_run_or_setup_time_run_end_time(self):
self.assertEqual(self.run5.endtime, None)
self.run5.run_time = '5:00'
self.run5.setup_time = '0'
self.run5.full_clean()

def test_removing_run_from_schedule(self):
self.run1.order = None
Expand Down
Loading

0 comments on commit 1811d91

Please sign in to comment.