From d8c5206e2ed23b9577146ddf3e66922136374399 Mon Sep 17 00:00:00 2001 From: jo Date: Sun, 19 Sep 2021 20:48:19 +0200 Subject: [PATCH] Fix cueout for overlapping starts & ends schedule --- api/libretimeapi/models/schedule.py | 42 ++++++++++--- api/libretimeapi/tests/models/__init__.py | 0 .../tests/models/test_schedule.py | 62 +++++++++++++++++++ 3 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 api/libretimeapi/tests/models/__init__.py create mode 100644 api/libretimeapi/tests/models/test_schedule.py diff --git a/api/libretimeapi/models/schedule.py b/api/libretimeapi/models/schedule.py index 314ef5ec2..f4bc7aa61 100644 --- a/api/libretimeapi/models/schedule.py +++ b/api/libretimeapi/models/schedule.py @@ -24,21 +24,45 @@ class Schedule(models.Model): def get_cueout(self): """ - Returns a cueout that is based on the current show. Cueout of a specific - item can potentially overrun the show that it is scheduled in. In that - case, the cueout should be the end of the show. This prevents the next - show having overlapping items playing. + Returns a scheduled item cueout that is based on the current show instance. + + Cueout of a specific item can potentially overrun the show that it is + scheduled in. In that case, the cueout should be the end of the show. + This prevents the next show having overlapping items playing. + + Cases: + - When the schedule ends before the end of the show instance, + return the stored cueout. + + - When the schedule starts before the end of the show instance + and ends after the show instance ends, + return timedelta between schedule starts and show instance ends. + + - When the schedule starts after the end of the show instance, + return the stored cue_out even if the schedule WILL NOT BE PLAYED. """ - if self.instance.ends < self.ends: + if self.starts < self.instance.ends and self.instance.ends < self.ends: return self.instance.ends - self.starts return self.cue_out def get_ends(self): """ - Returns an item end that is based on the current show. Ends of a - specific item can potentially overrun the show that it is scheduled in. - In that case, the end should be the end of the show. This prevents the - next show having overlapping items playing. + Returns a scheduled item ends that is based on the current show instance. + + End of a specific item can potentially overrun the show that it is + scheduled in. In that case, the end should be the end of the show. + This prevents the next show having overlapping items playing. + + Cases: + - When the schedule ends before the end of the show instance, + return the scheduled item ends. + + - When the schedule starts before the end of the show instance + and ends after the show instance ends, + return the show instance ends. + + - When the schedule starts after the end of the show instance, + return the show instance ends. """ if self.instance.ends < self.ends: return self.instance.ends diff --git a/api/libretimeapi/tests/models/__init__.py b/api/libretimeapi/tests/models/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/api/libretimeapi/tests/models/test_schedule.py b/api/libretimeapi/tests/models/test_schedule.py new file mode 100644 index 000000000..b04e25dd8 --- /dev/null +++ b/api/libretimeapi/tests/models/test_schedule.py @@ -0,0 +1,62 @@ +from datetime import datetime, timedelta + +from django.test import SimpleTestCase +from libretimeapi.models import Schedule, Show, ShowInstance + + +class TestSchedule(SimpleTestCase): + def test_get_cueout(self): + show_instance = ShowInstance( + created=datetime(year=2021, month=10, day=1, hour=12), + starts=datetime(year=2021, month=10, day=2, hour=1), + ends=datetime(year=2021, month=10, day=2, hour=2), + ) + + length = timedelta(minutes=10) + cue_in = timedelta(seconds=1) + cue_out = length - timedelta(seconds=4) + + # No overlapping schedule datetimes, normal usecase: + s1_starts = datetime(year=2021, month=10, day=2, hour=1, minute=30) + s1_ends = s1_starts + length + + s1 = Schedule( + starts=s1_starts, + ends=s1_ends, + cue_in=cue_in, + cue_out=cue_out, + instance=show_instance, + ) + + self.assertEqual(s1.get_cueout(), cue_out) + self.assertEqual(s1.get_ends(), s1_ends) + + # Mixed overlapping schedule datetimes (only ends is overlapping): + s2_starts = datetime(year=2021, month=10, day=2, hour=1, minute=55) + s2_ends = s2_starts + length + + s2 = Schedule( + starts=s2_starts, + ends=s2_ends, + cue_in=cue_in, + cue_out=cue_out, + instance=show_instance, + ) + + self.assertEqual(s2.get_cueout(), timedelta(minutes=5)) + self.assertEqual(s2.get_ends(), show_instance.ends) + + # Fully overlapping schedule datetimes (starts and ends are overlapping): + s3_starts = datetime(year=2021, month=10, day=2, hour=2, minute=1) + s3_ends = s3_starts + length + + s3 = Schedule( + starts=s3_starts, + ends=s3_ends, + cue_in=cue_in, + cue_out=cue_out, + instance=show_instance, + ) + + self.assertEqual(s3.get_cueout(), cue_out) + self.assertEqual(s3.get_ends(), show_instance.ends)