|
|
|
@ -1151,6 +1151,212 @@ namespace ErsatzTV.Core.Tests.Scheduling |
|
|
|
result.Anchor.NextScheduleItem.Should().Be(items[1]); |
|
|
|
result.Anchor.NextScheduleItem.Should().Be(items[1]); |
|
|
|
result.Anchor.DurationFinish.Should().Be(HoursAfterMidnight(6).UtcDateTime); |
|
|
|
result.Anchor.DurationFinish.Should().Be(HoursAfterMidnight(6).UtcDateTime); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[Test] |
|
|
|
|
|
|
|
public async Task Alternating_Duration_With_Filler_Should_Alternate_Schedule_Items() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var collectionOne = new Collection |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Id = 1, |
|
|
|
|
|
|
|
Name = "Duration Items 1", |
|
|
|
|
|
|
|
MediaItems = new List<MediaItem> |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
TestMovie(1, TimeSpan.FromMinutes(55), new DateTime(2020, 1, 1)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var collectionTwo = new Collection |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Id = 2, |
|
|
|
|
|
|
|
Name = "Duration Items 2", |
|
|
|
|
|
|
|
MediaItems = new List<MediaItem> |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
TestMovie(2, TimeSpan.FromMinutes(55), new DateTime(2020, 1, 1)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var collectionThree = new Collection |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Id = 3, |
|
|
|
|
|
|
|
Name = "Filler Items", |
|
|
|
|
|
|
|
MediaItems = new List<MediaItem> |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
TestMovie(3, TimeSpan.FromMinutes(5), new DateTime(2020, 1, 1)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var fakeRepository = new FakeMediaCollectionRepository( |
|
|
|
|
|
|
|
Map( |
|
|
|
|
|
|
|
(collectionOne.Id, collectionOne.MediaItems.ToList()), |
|
|
|
|
|
|
|
(collectionTwo.Id, collectionTwo.MediaItems.ToList()), |
|
|
|
|
|
|
|
(collectionThree.Id, collectionThree.MediaItems.ToList()))); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var items = new List<ProgramScheduleItem> |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
new ProgramScheduleItemDuration |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Id = 1, |
|
|
|
|
|
|
|
Index = 1, |
|
|
|
|
|
|
|
Collection = collectionOne, |
|
|
|
|
|
|
|
CollectionId = collectionOne.Id, |
|
|
|
|
|
|
|
StartTime = null, |
|
|
|
|
|
|
|
PlayoutDuration = TimeSpan.FromHours(3), |
|
|
|
|
|
|
|
PlaybackOrder = PlaybackOrder.Chronological, |
|
|
|
|
|
|
|
TailMode = TailMode.Filler, |
|
|
|
|
|
|
|
TailCollectionType = ProgramScheduleItemCollectionType.Collection, |
|
|
|
|
|
|
|
TailCollection = collectionThree, |
|
|
|
|
|
|
|
TailCollectionId = collectionThree.Id |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
new ProgramScheduleItemDuration |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Id = 2, |
|
|
|
|
|
|
|
Index = 2, |
|
|
|
|
|
|
|
Collection = collectionTwo, |
|
|
|
|
|
|
|
CollectionId = collectionTwo.Id, |
|
|
|
|
|
|
|
StartTime = null, |
|
|
|
|
|
|
|
PlayoutDuration = TimeSpan.FromHours(3), |
|
|
|
|
|
|
|
PlaybackOrder = PlaybackOrder.Chronological, |
|
|
|
|
|
|
|
TailMode = TailMode.Filler, |
|
|
|
|
|
|
|
TailCollectionType = ProgramScheduleItemCollectionType.Collection, |
|
|
|
|
|
|
|
TailCollection = collectionThree, |
|
|
|
|
|
|
|
TailCollectionId = collectionThree.Id |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var playout = new Playout |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ProgramSchedule = new ProgramSchedule |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Items = items |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
Channel = new Channel(Guid.Empty) { Id = 1, Name = "Test Channel" }, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var configRepo = new Mock<IConfigElementRepository>(); |
|
|
|
|
|
|
|
var televisionRepo = new FakeTelevisionRepository(); |
|
|
|
|
|
|
|
var artistRepo = new Mock<IArtistRepository>(); |
|
|
|
|
|
|
|
var builder = new PlayoutBuilder( |
|
|
|
|
|
|
|
configRepo.Object, |
|
|
|
|
|
|
|
fakeRepository, |
|
|
|
|
|
|
|
televisionRepo, |
|
|
|
|
|
|
|
artistRepo.Object, |
|
|
|
|
|
|
|
_logger); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DateTimeOffset start = HoursAfterMidnight(0); |
|
|
|
|
|
|
|
DateTimeOffset finish = start + TimeSpan.FromHours(6); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Playout result = await builder.BuildPlayoutItems(playout, start, finish); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result.Items.Count.Should().Be(12); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result.Items[0].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromMinutes(0)); |
|
|
|
|
|
|
|
result.Items[0].MediaItemId.Should().Be(1); |
|
|
|
|
|
|
|
result.Items[1].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromMinutes(55)); |
|
|
|
|
|
|
|
result.Items[1].MediaItemId.Should().Be(1); |
|
|
|
|
|
|
|
result.Items[2].StartOffset.TimeOfDay.Should().Be(new TimeSpan(1, 50, 0)); |
|
|
|
|
|
|
|
result.Items[2].MediaItemId.Should().Be(1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result.Items[3].StartOffset.TimeOfDay.Should().Be(new TimeSpan(2, 45, 0)); |
|
|
|
|
|
|
|
result.Items[3].MediaItemId.Should().Be(3); |
|
|
|
|
|
|
|
result.Items[4].StartOffset.TimeOfDay.Should().Be(new TimeSpan(2, 50, 0)); |
|
|
|
|
|
|
|
result.Items[4].MediaItemId.Should().Be(3); |
|
|
|
|
|
|
|
result.Items[5].StartOffset.TimeOfDay.Should().Be(new TimeSpan(2, 55, 0)); |
|
|
|
|
|
|
|
result.Items[5].MediaItemId.Should().Be(3); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result.Items[6].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(3)); |
|
|
|
|
|
|
|
result.Items[6].MediaItemId.Should().Be(2); |
|
|
|
|
|
|
|
result.Items[7].StartOffset.TimeOfDay.Should().Be(new TimeSpan(3, 55, 0)); |
|
|
|
|
|
|
|
result.Items[7].MediaItemId.Should().Be(2); |
|
|
|
|
|
|
|
result.Items[8].StartOffset.TimeOfDay.Should().Be(new TimeSpan(4, 50, 0)); |
|
|
|
|
|
|
|
result.Items[8].MediaItemId.Should().Be(2); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result.Items[9].StartOffset.TimeOfDay.Should().Be(new TimeSpan(5, 45, 0)); |
|
|
|
|
|
|
|
result.Items[9].MediaItemId.Should().Be(3); |
|
|
|
|
|
|
|
result.Items[10].StartOffset.TimeOfDay.Should().Be(new TimeSpan(5, 50, 0)); |
|
|
|
|
|
|
|
result.Items[10].MediaItemId.Should().Be(3); |
|
|
|
|
|
|
|
result.Items[11].StartOffset.TimeOfDay.Should().Be(new TimeSpan(5, 55, 0)); |
|
|
|
|
|
|
|
result.Items[11].MediaItemId.Should().Be(3); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result.Anchor.NextScheduleItem.Should().Be(items[0]); |
|
|
|
|
|
|
|
result.Anchor.DurationFinish.Should().BeNull(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[Test] |
|
|
|
|
|
|
|
public async Task Duration_Should_Skip_Items_That_Are_Too_Long() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var collectionOne = new Collection |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Id = 1, |
|
|
|
|
|
|
|
Name = "Duration Items 1", |
|
|
|
|
|
|
|
MediaItems = new List<MediaItem> |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
TestMovie(1, TimeSpan.FromHours(2), new DateTime(2020, 1, 1)), |
|
|
|
|
|
|
|
TestMovie(2, TimeSpan.FromHours(1), new DateTime(2020, 1, 1)), |
|
|
|
|
|
|
|
TestMovie(3, TimeSpan.FromHours(2), new DateTime(2020, 1, 1)), |
|
|
|
|
|
|
|
TestMovie(4, TimeSpan.FromHours(1), new DateTime(2020, 1, 1)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var fakeRepository = |
|
|
|
|
|
|
|
new FakeMediaCollectionRepository(Map((collectionOne.Id, collectionOne.MediaItems.ToList()))); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var items = new List<ProgramScheduleItem> |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
new ProgramScheduleItemDuration |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Id = 1, |
|
|
|
|
|
|
|
Index = 1, |
|
|
|
|
|
|
|
Collection = collectionOne, |
|
|
|
|
|
|
|
CollectionId = collectionOne.Id, |
|
|
|
|
|
|
|
StartTime = null, |
|
|
|
|
|
|
|
PlayoutDuration = TimeSpan.FromHours(1), |
|
|
|
|
|
|
|
PlaybackOrder = PlaybackOrder.Chronological, |
|
|
|
|
|
|
|
TailMode = TailMode.None, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var playout = new Playout |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ProgramSchedule = new ProgramSchedule |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Items = items |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
Channel = new Channel(Guid.Empty) { Id = 1, Name = "Test Channel" }, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var configRepo = new Mock<IConfigElementRepository>(); |
|
|
|
|
|
|
|
var televisionRepo = new FakeTelevisionRepository(); |
|
|
|
|
|
|
|
var artistRepo = new Mock<IArtistRepository>(); |
|
|
|
|
|
|
|
var builder = new PlayoutBuilder( |
|
|
|
|
|
|
|
configRepo.Object, |
|
|
|
|
|
|
|
fakeRepository, |
|
|
|
|
|
|
|
televisionRepo, |
|
|
|
|
|
|
|
artistRepo.Object, |
|
|
|
|
|
|
|
_logger); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DateTimeOffset start = HoursAfterMidnight(0); |
|
|
|
|
|
|
|
DateTimeOffset finish = start + TimeSpan.FromHours(6); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Playout result = await builder.BuildPlayoutItems(playout, start, finish); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result.Items.Count.Should().Be(6); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result.Items[0].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(0)); |
|
|
|
|
|
|
|
result.Items[0].MediaItemId.Should().Be(2); |
|
|
|
|
|
|
|
result.Items[1].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(1)); |
|
|
|
|
|
|
|
result.Items[1].MediaItemId.Should().Be(4); |
|
|
|
|
|
|
|
result.Items[2].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(2)); |
|
|
|
|
|
|
|
result.Items[2].MediaItemId.Should().Be(2); |
|
|
|
|
|
|
|
result.Items[3].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(3)); |
|
|
|
|
|
|
|
result.Items[3].MediaItemId.Should().Be(4); |
|
|
|
|
|
|
|
result.Items[4].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(4)); |
|
|
|
|
|
|
|
result.Items[4].MediaItemId.Should().Be(2); |
|
|
|
|
|
|
|
result.Items[5].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(5)); |
|
|
|
|
|
|
|
result.Items[5].MediaItemId.Should().Be(4); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result.Anchor.NextScheduleItem.Should().Be(items[0]); |
|
|
|
|
|
|
|
result.Anchor.DurationFinish.Should().BeNull(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static DateTimeOffset HoursAfterMidnight(int hours) |
|
|
|
private static DateTimeOffset HoursAfterMidnight(int hours) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|