using System.Collections.Generic; using FizzWare.NBuilder; using FluentAssertions; using Moq; using NUnit.Framework; using NzbDrone.Common.Disk; using NzbDrone.Core.Books; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Download; using NzbDrone.Core.Download.TrackedDownloads; using NzbDrone.Core.History; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles.BookImport; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Test.Framework; using NzbDrone.Test.Common; namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests { [TestFixture] public class ImportFixture : CoreTest { private TrackedDownload _trackedDownload; [SetUp] public void Setup() { var completed = Builder.CreateNew() .With(h => h.Status = DownloadItemStatus.Completed) .With(h => h.OutputPath = new OsPath(@"C:\DropFolder\MyDownload".AsOsAgnostic())) .With(h => h.Title = "Drone.S01E01.HDTV") .Build(); var remoteBook = BuildRemoteBook(); _trackedDownload = Builder.CreateNew() .With(c => c.State = TrackedDownloadState.Downloading) .With(c => c.ImportItem = completed) .With(c => c.DownloadItem = completed) .With(c => c.RemoteBook = remoteBook) .Build(); Mocker.GetMock() .SetupGet(c => c.Definition) .Returns(new DownloadClientDefinition { Id = 1, Name = "testClient" }); Mocker.GetMock() .Setup(c => c.Get(It.IsAny())) .Returns(Mocker.GetMock().Object); Mocker.GetMock() .Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId)) .Returns(new History.History()); Mocker.GetMock() .Setup(s => s.GetAuthor("Drone.S01E01.HDTV")) .Returns(remoteBook.Author); } private Book CreateBook(int id) { return new Book { Id = id }; } private RemoteBook BuildRemoteBook() { return new RemoteBook { Author = new Author(), Books = new List { CreateBook(1) } }; } private void GivenABadlyNamedDownload() { _trackedDownload.RemoteBook.Author = null; _trackedDownload.DownloadItem.DownloadId = "1234"; _trackedDownload.DownloadItem.Title = "Droned Pilot"; // Set a badly named download Mocker.GetMock() .Setup(s => s.MostRecentForDownloadId(It.Is(i => i == "1234"))) .Returns(new History.History() { SourceTitle = "Droned S01E01" }); Mocker.GetMock() .Setup(s => s.GetAuthor(It.IsAny())) .Returns((Author)null); Mocker.GetMock() .Setup(s => s.GetAuthor("Droned S01E01")) .Returns(BuildRemoteBook().Author); } private void GivenAuthorMatch() { Mocker.GetMock() .Setup(s => s.GetAuthor(It.IsAny())) .Returns(_trackedDownload.RemoteBook.Author); } [Test] public void should_not_mark_as_imported_if_all_files_were_rejected() { Mocker.GetMock() .Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new List { new ImportResult( new ImportDecision( new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }, new Rejection("Rejected!")), "Test Failure"), new ImportResult( new ImportDecision( new LocalBook { Path = @"C:\TestPath\Droned.S01E02.mkv".AsOsAgnostic() }, new Rejection("Rejected!")), "Test Failure") }); Subject.Import(_trackedDownload); Mocker.GetMock() .Verify(v => v.PublishEvent(It.IsAny()), Times.Never()); AssertNotImported(); } [Test] public void should_not_mark_as_imported_if_no_tracks_were_parsed() { Mocker.GetMock() .Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new List { new ImportResult( new ImportDecision( new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }, new Rejection("Rejected!")), "Test Failure"), new ImportResult( new ImportDecision( new LocalBook { Path = @"C:\TestPath\Droned.S01E02.mkv".AsOsAgnostic() }, new Rejection("Rejected!")), "Test Failure") }); _trackedDownload.RemoteBook.Books.Clear(); Subject.Import(_trackedDownload); AssertNotImported(); } [Test] public void should_not_mark_as_imported_if_all_files_were_skipped() { Mocker.GetMock() .Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new List { new ImportResult(new ImportDecision(new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }), "Test Failure"), new ImportResult(new ImportDecision(new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }), "Test Failure") }); Subject.Import(_trackedDownload); AssertNotImported(); } [Test] public void should_mark_as_imported_if_all_tracks_were_imported_but_extra_files_were_not() { GivenAuthorMatch(); _trackedDownload.RemoteBook.Books = new List { CreateBook(1) }; Mocker.GetMock() .Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new List { new ImportResult(new ImportDecision(new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() })), new ImportResult(new ImportDecision(new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }), "Test Failure") }); Subject.Import(_trackedDownload); AssertImported(); } [Test] public void should_not_mark_as_imported_if_some_tracks_were_not_imported() { _trackedDownload.RemoteBook.Books = new List { CreateBook(1), CreateBook(1), CreateBook(1) }; Mocker.GetMock() .Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new List { new ImportResult(new ImportDecision(new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() })), new ImportResult(new ImportDecision(new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() })), new ImportResult(new ImportDecision(new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }), "Test Failure"), new ImportResult(new ImportDecision(new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }), "Test Failure"), new ImportResult(new ImportDecision(new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }), "Test Failure") }); var history = Builder.CreateListOfSize(2) .BuildList(); Mocker.GetMock() .Setup(s => s.FindByDownloadId(It.IsAny())) .Returns(history); Mocker.GetMock() .Setup(s => s.IsImported(_trackedDownload, history)) .Returns(true); Subject.Import(_trackedDownload); AssertNotImported(); } [Test] public void should_not_mark_as_imported_if_some_of_episodes_were_not_imported_including_history() { var books = Builder.CreateListOfSize(3).BuildList(); _trackedDownload.RemoteBook.Books = books; Mocker.GetMock() .Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new List { new ImportResult(new ImportDecision(new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv" })), new ImportResult(new ImportDecision(new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv" }), "Test Failure"), new ImportResult(new ImportDecision(new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv" }), "Test Failure") }); var history = Builder.CreateListOfSize(2) .BuildList(); Mocker.GetMock() .Setup(s => s.FindByDownloadId(It.IsAny())) .Returns(history); Mocker.GetMock() .Setup(s => s.IsImported(It.IsAny(), It.IsAny>())) .Returns(false); Subject.Import(_trackedDownload); AssertNotImported(); } [Test] public void should_mark_as_imported_if_all_tracks_were_imported() { _trackedDownload.RemoteBook.Books = new List { CreateBook(1) }; Mocker.GetMock() .Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new List { new ImportResult( new ImportDecision( new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() })), new ImportResult( new ImportDecision( new LocalBook { Path = @"C:\TestPath\Droned.S01E02.mkv".AsOsAgnostic() })) }); Subject.Import(_trackedDownload); AssertImported(); } [Test] public void should_mark_as_imported_if_all_episodes_were_imported_including_history() { var books = Builder.CreateListOfSize(2).BuildList(); _trackedDownload.RemoteBook.Books = books; Mocker.GetMock() .Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new List { new ImportResult( new ImportDecision( new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv", Book = books[0] })), new ImportResult( new ImportDecision( new LocalBook { Path = @"C:\TestPath\Droned.S01E02.mkv", Book = books[1] }), "Test Failure") }); var history = Builder.CreateListOfSize(2) .BuildList(); Mocker.GetMock() .Setup(s => s.FindByDownloadId(It.IsAny())) .Returns(history); Mocker.GetMock() .Setup(s => s.IsImported(It.IsAny(), It.IsAny>())) .Returns(true); Subject.Import(_trackedDownload); AssertImported(); } [Test] public void should_mark_as_imported_if_the_download_can_be_tracked_using_the_source_seriesid() { GivenABadlyNamedDownload(); Mocker.GetMock() .Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new List { new ImportResult(new ImportDecision(new LocalBook { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() })) }); Subject.Import(_trackedDownload); AssertImported(); } private void AssertNotImported() { Mocker.GetMock() .Verify(v => v.PublishEvent(It.IsAny()), Times.Never()); _trackedDownload.State.Should().Be(TrackedDownloadState.ImportFailed); } private void AssertImported() { Mocker.GetMock() .Verify(v => v.ProcessPath(_trackedDownload.DownloadItem.OutputPath.FullPath, ImportMode.Auto, _trackedDownload.RemoteBook.Author, _trackedDownload.DownloadItem), Times.Once()); Mocker.GetMock() .Verify(v => v.PublishEvent(It.IsAny()), Times.Once()); _trackedDownload.State.Should().Be(TrackedDownloadState.Imported); } } }