From 2d0b87b558590ecdc1a7b6a4d87661b3cf8a05a6 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 29 Jun 2016 09:42:17 +0100 Subject: [PATCH] Fixed a bit of a stupid bug in the resetter and added unit tests around it to make sure this never happens again. --- .../NotificationServiceTests.cs | 272 ++++++++--------- .../PlexRequests.Services.Tests.csproj | 275 +++++++++--------- .../UserRequestLimitResetterTests.cs | 151 ++++++++++ PlexRequests.Services.Tests/packages.config | 15 +- .../Jobs/UserRequestLimitResetter.cs | 3 +- PlexRequests.UI/Views/Admin/Status.cshtml | 140 ++++----- 6 files changed, 507 insertions(+), 349 deletions(-) create mode 100644 PlexRequests.Services.Tests/UserRequestLimitResetterTests.cs diff --git a/PlexRequests.Services.Tests/NotificationServiceTests.cs b/PlexRequests.Services.Tests/NotificationServiceTests.cs index 940bcedda..a7df1c791 100644 --- a/PlexRequests.Services.Tests/NotificationServiceTests.cs +++ b/PlexRequests.Services.Tests/NotificationServiceTests.cs @@ -1,137 +1,137 @@ -#region Copyright -/************************************************************************ - Copyright (c) 2016 Jamie Rees - File: NotificationServiceTests.cs - Created By: Jamie Rees - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ************************************************************************/ -#endregion -using System; -using System.Threading.Tasks; - -using Moq; - -using NUnit.Framework; - -using PlexRequests.Services.Interfaces; -using PlexRequests.Services.Notification; - -namespace PlexRequests.Services.Tests -{ - [TestFixture] - public class NotificationServiceTests - { - public NotificationService NotificationService { get; set; } - - [SetUp] - public void Setup() - { - NotificationService = new NotificationService(); - } - - [Test] - public void SubscribeNewNotifier() - { - var notificationMock = new Mock(); - notificationMock.SetupGet(x => x.NotificationName).Returns("Notification1"); - NotificationService.Subscribe(notificationMock.Object); - - Assert.That(NotificationService.Observers["Notification1"], Is.Not.Null); - Assert.That(NotificationService.Observers.Count, Is.EqualTo(1)); - } - - [Test] - public void SubscribeExistingNotifier() - { - var notificationMock1 = new Mock(); - var notificationMock2 = new Mock(); - notificationMock1.SetupGet(x => x.NotificationName).Returns("Notification1"); - notificationMock2.SetupGet(x => x.NotificationName).Returns("Notification1"); - NotificationService.Subscribe(notificationMock1.Object); - - Assert.That(NotificationService.Observers["Notification1"], Is.Not.Null); - Assert.That(NotificationService.Observers.Count, Is.EqualTo(1)); - - NotificationService.Subscribe(notificationMock2.Object); - - Assert.That(NotificationService.Observers["Notification1"], Is.Not.Null); - Assert.That(NotificationService.Observers.Count, Is.EqualTo(1)); - } - - [Test] - public void UnSubscribeMissingNotifier() - { - var notificationMock = new Mock(); - notificationMock.SetupGet(x => x.NotificationName).Returns("Notification1"); - NotificationService.UnSubscribe(notificationMock.Object); - - Assert.That(NotificationService.Observers.Count, Is.EqualTo(0)); - } - - [Test] - public void UnSubscribeNotifier() - { - var notificationMock = new Mock(); - notificationMock.SetupGet(x => x.NotificationName).Returns("Notification1"); - NotificationService.Subscribe(notificationMock.Object); - Assert.That(NotificationService.Observers.Count, Is.EqualTo(1)); - - NotificationService.UnSubscribe(notificationMock.Object); - Assert.That(NotificationService.Observers.Count, Is.EqualTo(0)); - } - - [Test] - public void PublishWithNoObservers() - { - Assert.DoesNotThrowAsync( - async() => - { await NotificationService.Publish(new NotificationModel()); }); - } - - [Test] - public async Task PublishAllNotifiers() - { - var notificationMock1 = new Mock(); - var notificationMock2 = new Mock(); - notificationMock1.SetupGet(x => x.NotificationName).Returns("Notification1"); - notificationMock2.SetupGet(x => x.NotificationName).Returns("Notification2"); - NotificationService.Subscribe(notificationMock1.Object); - NotificationService.Subscribe(notificationMock2.Object); - - Assert.That(NotificationService.Observers.Count, Is.EqualTo(2)); - var model = new NotificationModel { Title = "abc", Body = "test" }; - await NotificationService.Publish(model); - - notificationMock1.Verify(x => x.NotifyAsync(model), Times.Once); - notificationMock2.Verify(x => x.NotifyAsync(model), Times.Once); - } - - [Test] - public async Task PublishWithException() - { - var notificationMock = new Mock(); - notificationMock.Setup(x => x.NotifyAsync(It.IsAny())).Throws(); - notificationMock.SetupGet(x => x.NotificationName).Returns("Notification1"); - NotificationService.Subscribe(notificationMock.Object); - await NotificationService.Publish(new NotificationModel()); - } - } +#region Copyright +/************************************************************************ + Copyright (c) 2016 Jamie Rees + File: NotificationServiceTests.cs + Created By: Jamie Rees + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ************************************************************************/ +#endregion +using System; +using System.Threading.Tasks; + +using Moq; + +using NUnit.Framework; + +using PlexRequests.Services.Interfaces; +using PlexRequests.Services.Notification; + +namespace PlexRequests.Services.Tests +{ + [TestFixture] + public class NotificationServiceTests + { + public NotificationService NotificationService { get; set; } + + [SetUp] + public void Setup() + { + NotificationService = new NotificationService(); + } + + [Test] + public void SubscribeNewNotifier() + { + var notificationMock = new Mock(); + notificationMock.SetupGet(x => x.NotificationName).Returns("Notification1"); + NotificationService.Subscribe(notificationMock.Object); + + Assert.That(NotificationService.Observers["Notification1"], Is.Not.Null); + Assert.That(NotificationService.Observers.Count, Is.EqualTo(1)); + } + + [Test] + public void SubscribeExistingNotifier() + { + var notificationMock1 = new Mock(); + var notificationMock2 = new Mock(); + notificationMock1.SetupGet(x => x.NotificationName).Returns("Notification1"); + notificationMock2.SetupGet(x => x.NotificationName).Returns("Notification1"); + NotificationService.Subscribe(notificationMock1.Object); + + Assert.That(NotificationService.Observers["Notification1"], Is.Not.Null); + Assert.That(NotificationService.Observers.Count, Is.EqualTo(1)); + + NotificationService.Subscribe(notificationMock2.Object); + + Assert.That(NotificationService.Observers["Notification1"], Is.Not.Null); + Assert.That(NotificationService.Observers.Count, Is.EqualTo(1)); + } + + [Test] + public void UnSubscribeMissingNotifier() + { + var notificationMock = new Mock(); + notificationMock.SetupGet(x => x.NotificationName).Returns("Notification1"); + NotificationService.UnSubscribe(notificationMock.Object); + + Assert.That(NotificationService.Observers.Count, Is.EqualTo(0)); + } + + [Test] + public void UnSubscribeNotifier() + { + var notificationMock = new Mock(); + notificationMock.SetupGet(x => x.NotificationName).Returns("Notification1"); + NotificationService.Subscribe(notificationMock.Object); + Assert.That(NotificationService.Observers.Count, Is.EqualTo(1)); + + NotificationService.UnSubscribe(notificationMock.Object); + Assert.That(NotificationService.Observers.Count, Is.EqualTo(0)); + } + + [Test] + public void PublishWithNoObservers() + { + Assert.DoesNotThrowAsync( + async() => + { await NotificationService.Publish(new NotificationModel()); }); + } + + [Test] + public async Task PublishAllNotifiers() + { + var notificationMock1 = new Mock(); + var notificationMock2 = new Mock(); + notificationMock1.SetupGet(x => x.NotificationName).Returns("Notification1"); + notificationMock2.SetupGet(x => x.NotificationName).Returns("Notification2"); + NotificationService.Subscribe(notificationMock1.Object); + NotificationService.Subscribe(notificationMock2.Object); + + Assert.That(NotificationService.Observers.Count, Is.EqualTo(2)); + var model = new NotificationModel { Title = "abc", Body = "test" }; + await NotificationService.Publish(model); + + notificationMock1.Verify(x => x.NotifyAsync(model), Times.Once); + notificationMock2.Verify(x => x.NotifyAsync(model), Times.Once); + } + + [Test] + public async Task PublishWithException() + { + var notificationMock = new Mock(); + notificationMock.Setup(x => x.NotifyAsync(It.IsAny())).Throws(); + notificationMock.SetupGet(x => x.NotificationName).Returns("Notification1"); + NotificationService.Subscribe(notificationMock.Object); + await NotificationService.Publish(new NotificationModel()); + } + } } \ No newline at end of file diff --git a/PlexRequests.Services.Tests/PlexRequests.Services.Tests.csproj b/PlexRequests.Services.Tests/PlexRequests.Services.Tests.csproj index 298d5e64d..dc79ac405 100644 --- a/PlexRequests.Services.Tests/PlexRequests.Services.Tests.csproj +++ b/PlexRequests.Services.Tests/PlexRequests.Services.Tests.csproj @@ -1,136 +1,141 @@ - - - - Debug - AnyCPU - {EAADB4AC-064F-4D3A-AFF9-64A33131A9A7} - Library - Properties - PlexRequests.Services.Tests - PlexRequests.Services.Tests - v4.5.2 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Common.Logging.3.0.0\lib\net40\Common.Logging.dll - True - - - ..\packages\Common.Logging.Core.3.0.0\lib\net40\Common.Logging.Core.dll - True - - - ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll - True - - - ..\packages\NUnit.3.2.0\lib\net45\nunit.framework.dll - True - - - ..\packages\Quartz.2.3.3\lib\net40\Quartz.dll - True - - - - - - - - - - - - - - - - - - - Designer - - - Designer - - - - - - {95834072-A675-415D-AA8F-877C91623810} - PlexRequests.Api.Interfaces - - - {CB37A5F8-6DFC-4554-99D3-A42B502E4591} - PlexRequests.Api.Models - - - {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581} - PlexRequests.Core - - - {1252336D-42A3-482A-804C-836E60173DFA} - PlexRequests.Helpers - - - {566EFA49-68F8-4716-9693-A6B3F2624DEA} - PlexRequests.Services - - - {92433867-2B7B-477B-A566-96C382427525} - PlexRequests.Store - - - - - - - False - - - False - - - False - - - False - - - - - - - + + + + Debug + AnyCPU + {EAADB4AC-064F-4D3A-AFF9-64A33131A9A7} + Library + Properties + PlexRequests.Services.Tests + PlexRequests.Services.Tests + v4.5.2 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Common.Logging.3.0.0\lib\net40\Common.Logging.dll + True + + + ..\packages\Common.Logging.Core.3.0.0\lib\net40\Common.Logging.Core.dll + True + + + ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll + True + + + ..\packages\NUnit.3.2.0\lib\net45\nunit.framework.dll + True + + + ..\packages\AutoFixture.3.40.0\lib\net40\Ploeh.AutoFixture.dll + True + + + ..\packages\Quartz.2.3.3\lib\net40\Quartz.dll + True + + + + + + + + + + + + + + + + + + + + Designer + + + Designer + + + + + + {95834072-A675-415D-AA8F-877C91623810} + PlexRequests.Api.Interfaces + + + {CB37A5F8-6DFC-4554-99D3-A42B502E4591} + PlexRequests.Api.Models + + + {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581} + PlexRequests.Core + + + {1252336D-42A3-482A-804C-836E60173DFA} + PlexRequests.Helpers + + + {566EFA49-68F8-4716-9693-A6B3F2624DEA} + PlexRequests.Services + + + {92433867-2B7B-477B-A566-96C382427525} + PlexRequests.Store + + + + + + + False + + + False + + + False + + + False + + + + + + + \ No newline at end of file diff --git a/PlexRequests.Services.Tests/UserRequestLimitResetterTests.cs b/PlexRequests.Services.Tests/UserRequestLimitResetterTests.cs new file mode 100644 index 000000000..b19cd65a3 --- /dev/null +++ b/PlexRequests.Services.Tests/UserRequestLimitResetterTests.cs @@ -0,0 +1,151 @@ +#region Copyright +/************************************************************************ + Copyright (c) 2016 Jamie Rees + File: NotificationServiceTests.cs + Created By: Jamie Rees + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ************************************************************************/ +#endregion +using System; +using System.Collections.Generic; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; + +using Moq; + +using NUnit.Framework; + +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; +using PlexRequests.Services.Interfaces; +using PlexRequests.Services.Jobs; +using PlexRequests.Services.Notification; +using PlexRequests.Store; +using PlexRequests.Store.Models; +using PlexRequests.Store.Repository; + +using Ploeh.AutoFixture; + +using Quartz; + +namespace PlexRequests.Services.Tests +{ + [TestFixture] + public class UserRequestLimitResetterTests + { + public UserRequestLimitResetter Resetter { get; set; } + private Mock JobMock { get; set; } + private Mock> RepoMock { get; set; } + private Mock> SettingsMock { get; set; } + private Mock ContextMock { get; set; } + private Fixture F { get; set; } + + [SetUp] + public void Setup() + { + F = new Fixture(); + JobMock = new Mock(); + RepoMock = new Mock>(); + SettingsMock = new Mock>(); + ContextMock = new Mock(); + + SettingsMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings()); + + Resetter = new UserRequestLimitResetter(JobMock.Object, RepoMock.Object, SettingsMock.Object); + } + + [TearDown] + public void Teardown() + { + SettingsMock.Verify(x => x.GetSettings(), Times.Once); + JobMock.Verify(x => x.Record(It.IsAny()), Times.Once()); + } + + [Test] + public void ResetTurnedOff() + { + SetupSettings(0, 0, 0); + Resetter = new UserRequestLimitResetter(JobMock.Object, RepoMock.Object, SettingsMock.Object); + + Resetter.Execute(ContextMock.Object); + + RepoMock.Verify(x => x.Delete(It.IsAny()), Times.Never); + } + + [TestCaseSource(nameof(ResetData))] + public void Reset(int movie, int tv, int album, RequestType type) + { + SetupSettings(movie, tv, album); + RepoMock.Setup(x => x.GetAll()).Returns(F.Build() + .With(x => x.FirstRequestDate, DateTime.Now.AddDays(-8)) + .With(x => x.RequestType, type).CreateMany()); + + Resetter = new UserRequestLimitResetter(JobMock.Object, RepoMock.Object, SettingsMock.Object); + + Resetter.Execute(ContextMock.Object); + + RepoMock.Verify(x => x.Delete(It.IsAny()), Times.Exactly(3)); + } + + [TestCaseSource(nameof(DoNotResetData))] + public void DoNotReset(int days, RequestType type) + { + SetupSettings(1, 1, 1); + RepoMock.Setup(x => x.GetAll()).Returns(F.Build() + .With(x => x.FirstRequestDate, DateTime.Now.AddDays(days)) + .With(x => x.RequestType, type).CreateMany()); + + Resetter = new UserRequestLimitResetter(JobMock.Object, RepoMock.Object, SettingsMock.Object); + + Resetter.Execute(ContextMock.Object); + + RepoMock.Verify(x => x.Delete(It.IsAny()), Times.Never); + } + + static readonly IEnumerable ResetData = new List + { + new TestCaseData(1,0,0,RequestType.Movie).SetName("Reset Movies"), + new TestCaseData(0,1,0,RequestType.TvShow).SetName("Reset TV Shows"), + new TestCaseData(0,0,1,RequestType.Album).SetName("Reset Albums"), + new TestCaseData(1,1,1,RequestType.Album).SetName("Reset Albums with all enabled"), + }; + + private static readonly IEnumerable DoNotResetData = new List + { + new TestCaseData(1, RequestType.Movie).SetName("1 Day(s)"), + new TestCaseData(-6, RequestType.TvShow).SetName("-6 Day(s)"), + new TestCaseData(-1, RequestType.TvShow).SetName("-1 Day(s)"), + new TestCaseData(-2, RequestType.Album).SetName("-2 Day(s)"), + new TestCaseData(-3, RequestType.TvShow).SetName("-3 Day(s)"), + new TestCaseData(-4, RequestType.Movie).SetName("-4 Day(s)"), + new TestCaseData(-5, RequestType.TvShow).SetName("-5 Day(s)"), + new TestCaseData(-6, RequestType.Movie).SetName("-6 Day(s)"), + new TestCaseData(0, RequestType.TvShow).SetName("0 Day(s)"), + }; + + private void SetupSettings(int movie, int tv, int album) + { + SettingsMock.Setup(x => x.GetSettings()) + .Returns(new PlexRequestSettings { MovieWeeklyRequestLimit = movie, TvWeeklyRequestLimit = tv, AlbumWeeklyRequestLimit = album }); + } + + } +} \ No newline at end of file diff --git a/PlexRequests.Services.Tests/packages.config b/PlexRequests.Services.Tests/packages.config index 50f0bcc7b..73921e638 100644 --- a/PlexRequests.Services.Tests/packages.config +++ b/PlexRequests.Services.Tests/packages.config @@ -1,8 +1,9 @@ - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/PlexRequests.Services/Jobs/UserRequestLimitResetter.cs b/PlexRequests.Services/Jobs/UserRequestLimitResetter.cs index 13bd34463..6e0c5421a 100644 --- a/PlexRequests.Services/Jobs/UserRequestLimitResetter.cs +++ b/PlexRequests.Services/Jobs/UserRequestLimitResetter.cs @@ -109,7 +109,8 @@ namespace PlexRequests.Services.Jobs var users = allUsers.Where(x => x.RequestType == type); foreach (var u in users) { - if (u.FirstRequestDate > DateTime.UtcNow.AddDays(-7)) + var daysDiff = (u.FirstRequestDate - DateTime.UtcNow.AddDays(-7)).Days; + if (daysDiff <= 0) { Repo.Delete(u); } diff --git a/PlexRequests.UI/Views/Admin/Status.cshtml b/PlexRequests.UI/Views/Admin/Status.cshtml index efea96a0f..16fd46cd5 100644 --- a/PlexRequests.UI/Views/Admin/Status.cshtml +++ b/PlexRequests.UI/Views/Admin/Status.cshtml @@ -1,71 +1,71 @@ -@using PlexRequests.UI.Helpers -@Html.Partial("_Sidebar") - -
-
- Status - - -
- - -
- -
- - @if (Model.UpdateAvailable) - { - -
- - } - else - { - - } - -
- - @if (Model.UpdateAvailable) - { -

- @Model.ReleaseTitle -

-
- - @Html.Raw(Model.ReleaseNotes) - } - - -
-
- - \ No newline at end of file