From 28e248046ad56390595f84172bbd5f5961325b4d Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 30 Sep 2022 20:07:38 +0100 Subject: [PATCH] =?UTF-8?q?fix(availability):=20=F0=9F=90=9B=20Fixed=20a?= =?UTF-8?q?=20issue=20with=20the=20availability=20checker=20after=20the=20?= =?UTF-8?q?previous=20update.=20Added=20full=20test=20coverage=20around=20?= =?UTF-8?q?that=20area?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Ombi.Hubs/NotificationHub.cs | 6 +- .../AvailabilityCheckerTests.cs | 199 ++++++++++++++++++ .../Jobs/ArrAvailabilityChecker.cs | 2 +- src/Ombi.Schedule/Jobs/AvailabilityChecker.cs | 8 +- .../Jobs/Emby/EmbyAvaliabilityChecker.cs | 2 +- .../Jellyfin/JellyfinAvaliabilityChecker.cs | 2 +- .../Jobs/Plex/PlexAvailabilityChecker.cs | 2 +- 7 files changed, 212 insertions(+), 9 deletions(-) create mode 100644 src/Ombi.Schedule.Tests/AvailabilityCheckerTests.cs diff --git a/src/Ombi.Hubs/NotificationHub.cs b/src/Ombi.Hubs/NotificationHub.cs index 54d13884a..5e211b093 100644 --- a/src/Ombi.Hubs/NotificationHub.cs +++ b/src/Ombi.Hubs/NotificationHub.cs @@ -24,7 +24,11 @@ namespace Ombi.Hubs { get { - return UsersOnline.Where(x => x.Value.Roles.Contains(OmbiRoles.Admin)).Select(x => x.Key).ToList(); + if (UsersOnline.Any()) + { + return UsersOnline.Where(x => x.Value.Roles.Contains(OmbiRoles.Admin)).Select(x => x.Key).ToList(); + } + return Enumerable.Empty().ToList(); } } diff --git a/src/Ombi.Schedule.Tests/AvailabilityCheckerTests.cs b/src/Ombi.Schedule.Tests/AvailabilityCheckerTests.cs new file mode 100644 index 000000000..41f51deee --- /dev/null +++ b/src/Ombi.Schedule.Tests/AvailabilityCheckerTests.cs @@ -0,0 +1,199 @@ +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; +using MockQueryable.Moq; +using Moq; +using Moq.AutoMock; +using NUnit.Framework; +using Ombi.Core; +using Ombi.Hubs; +using Ombi.Notifications.Models; +using Ombi.Schedule.Jobs; +using Ombi.Store.Entities; +using Ombi.Store.Entities.Requests; +using Ombi.Store.Repository.Requests; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Ombi.Schedule.Tests +{ + [TestFixture] + public class AvailabilityCheckerTests + { + private AutoMocker _mocker; + private TestAvailabilityChecker _subject; + + [SetUp] + public void SetUp() + { + _mocker = new AutoMocker(); + Mock mockClients = new Mock(); + Mock mockClientProxy = new Mock(); + mockClients.Setup(clients => clients.Clients(It.IsAny>())).Returns(mockClientProxy.Object); + + var hubContext = new Mock>(); + hubContext.Setup(x => x.Clients).Returns(() => mockClients.Object); + _mocker.Use(hubContext); + + + _subject = _mocker.CreateInstance(); + } + + [Test] + public async Task All_Episodes_Are_Available_In_Request() + { + var request = new ChildRequests + { + Title = "Test", + Id = 1, + RequestedUser = new OmbiUser { Email = "" }, + SeasonRequests = new List + { + new SeasonRequests + { + Episodes = new List + { + new EpisodeRequests + { + Available = false, + EpisodeNumber = 1, + Season = new SeasonRequests + { + SeasonNumber = 1 + } + }, + new EpisodeRequests + { + Available = false, + EpisodeNumber = 2, + Season = new SeasonRequests + { + SeasonNumber = 1 + } + } + } + } + } + }; + + var databaseEpisodes = new List + { + new PlexEpisode + { + EpisodeNumber = 1, + SeasonNumber = 1, + }, + new PlexEpisode + { + EpisodeNumber = 2, + SeasonNumber = 1, + }, + }.AsQueryable().BuildMock().Object; + + await _subject.ProcessTvShow(databaseEpisodes, request); + + Assert.Multiple(() => + { + Assert.That(request.Available, Is.True); + Assert.That(request.MarkedAsAvailable, Is.Not.Null); + Assert.That(request.SeasonRequests[0].Episodes[0].Available, Is.True); + Assert.That(request.SeasonRequests[0].Episodes[1].Available, Is.True); + }); + + Assert.Multiple(() => + { + _mocker.Verify(x => x.Save(), Times.Exactly(2)); + _mocker.Verify(x => x.Notify(It.Is(x => x.NotificationType == Helpers.NotificationType.RequestAvailable && x.RequestId == 1)), Times.Once); + }); + } + + [Test] + public async Task All_One_Episode_Is_Available_In_Request() + { + var request = new ChildRequests + { + Title = "Test", + Id = 1, + RequestedUser = new OmbiUser { Email = "" }, + SeasonRequests = new List + { + new SeasonRequests + { + Episodes = new List + { + new EpisodeRequests + { + Available = false, + EpisodeNumber = 1, + Season = new SeasonRequests + { + SeasonNumber = 1 + } + }, + new EpisodeRequests + { + Available = false, + EpisodeNumber = 2, + Season = new SeasonRequests + { + SeasonNumber = 1 + } + }, + new EpisodeRequests + { + Available = true, + EpisodeNumber = 3, + Season = new SeasonRequests + { + SeasonNumber = 1 + } + } + } + } + } + }; + + var databaseEpisodes = new List + { + new PlexEpisode + { + EpisodeNumber = 1, + SeasonNumber = 1, + }, + new PlexEpisode + { + EpisodeNumber = 3, + SeasonNumber = 1, + }, + }.AsQueryable().BuildMock().Object; + + await _subject.ProcessTvShow(databaseEpisodes, request); + + Assert.Multiple(() => + { + Assert.That(request.Available, Is.False); + Assert.That(request.MarkedAsAvailable, Is.Null); + Assert.That(request.SeasonRequests[0].Episodes[0].Available, Is.True); + Assert.That(request.SeasonRequests[0].Episodes[1].Available, Is.False); + }); + + Assert.Multiple(() => + { + _mocker.Verify(x => x.Save(), Times.Once); + _mocker.Verify(x => x.Notify(It.Is(x => x.NotificationType == Helpers.NotificationType.PartiallyAvailable && x.RequestId == 1)), Times.Once); + }); + } + } + + + public class TestAvailabilityChecker : AvailabilityChecker + { + public TestAvailabilityChecker(ITvRequestRepository tvRequest, INotificationHelper notification, ILogger log, IHubContext hub) : base(tvRequest, notification, log, hub) + { + } + + public new Task ProcessTvShow(IQueryable seriesEpisodes, ChildRequests child) => base.ProcessTvShow(seriesEpisodes, child); + } +} diff --git a/src/Ombi.Schedule/Jobs/ArrAvailabilityChecker.cs b/src/Ombi.Schedule/Jobs/ArrAvailabilityChecker.cs index 756343c76..c40d4fc46 100644 --- a/src/Ombi.Schedule/Jobs/ArrAvailabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/ArrAvailabilityChecker.cs @@ -132,7 +132,7 @@ namespace Ombi.Schedule.Jobs.Radarr continue; } - ProcessTvShow(seriesEpisodes, child); + await ProcessTvShow(seriesEpisodes, child); } await _tvRepo.Save(); diff --git a/src/Ombi.Schedule/Jobs/AvailabilityChecker.cs b/src/Ombi.Schedule/Jobs/AvailabilityChecker.cs index 1183e3f60..1ea87a76d 100644 --- a/src/Ombi.Schedule/Jobs/AvailabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/AvailabilityChecker.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -14,7 +15,7 @@ using Ombi.Store.Repository.Requests; namespace Ombi.Schedule.Jobs { - public class AvailabilityChecker + public abstract class AvailabilityChecker { protected readonly ITvRequestRepository _tvRepo; protected readonly INotificationHelper _notificationService; @@ -30,9 +31,8 @@ namespace Ombi.Schedule.Jobs _hub = hub; } - protected async void ProcessTvShow(IQueryable seriesEpisodes, ChildRequests child) + protected async Task ProcessTvShow(IQueryable seriesEpisodes, ChildRequests child) { - var availableEpisode = new List(); foreach (var season in child.SeasonRequests) { @@ -71,7 +71,7 @@ namespace Ombi.Schedule.Jobs // We have ful-fulled this request! child.Available = true; child.MarkedAsAvailable = DateTime.UtcNow; - await _hub.Clients.Clients(NotificationHub.AdminConnectionIds) + await _hub?.Clients?.Clients(NotificationHub.AdminConnectionIds)? .SendAsync(NotificationHub.NotificationEvent, "Availability Checker found some new available Shows!"); _log.LogInformation("Child request {0} is now available, sending notification", $"{child.Title} - {child.Id}"); diff --git a/src/Ombi.Schedule/Jobs/Emby/EmbyAvaliabilityChecker.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyAvaliabilityChecker.cs index 7e969e566..edcc853bb 100644 --- a/src/Ombi.Schedule/Jobs/Emby/EmbyAvaliabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyAvaliabilityChecker.cs @@ -157,7 +157,7 @@ namespace Ombi.Schedule.Jobs.Emby x.Series.Title == child.Title); } - ProcessTvShow(seriesEpisodes, child); + await ProcessTvShow(seriesEpisodes, child); } await _tvRepo.Save(); diff --git a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinAvaliabilityChecker.cs b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinAvaliabilityChecker.cs index bc790a2c2..4c54fc25e 100644 --- a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinAvaliabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinAvaliabilityChecker.cs @@ -185,7 +185,7 @@ namespace Ombi.Schedule.Jobs.Jellyfin x.Series.Title == child.Title); } - ProcessTvShow(seriesEpisodes, child); + await ProcessTvShow(seriesEpisodes, child); } await _tvRepo.Save(); diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs b/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs index 6e467b0a0..34cd0964a 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs @@ -105,7 +105,7 @@ namespace Ombi.Schedule.Jobs.Plex } - ProcessTvShow(seriesEpisodes, child); + await ProcessTvShow(seriesEpisodes, child); } await _tvRepo.Save();