using System; using System.Collections.Generic; using System.IO; using System.IO.Abstractions; using System.Linq; using System.Net; using FluentAssertions; using Moq; using NUnit.Framework; using NzbDrone.Common.Disk; using NzbDrone.Common.Http; using NzbDrone.Core.Download; using NzbDrone.Core.Download.Clients.Blackhole; using NzbDrone.Core.Exceptions; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles.TorrentInfo; using NzbDrone.Core.Parser.Model; using NzbDrone.Test.Common; namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole { [TestFixture] public class TorrentBlackholeFixture : DownloadClientFixtureBase { protected string _completedDownloadFolder; protected string _blackholeFolder; protected string _filePath; protected string _magnetFilePath; [SetUp] public void Setup() { _completedDownloadFolder = @"c:\blackhole\completed".AsOsAgnostic(); _blackholeFolder = @"c:\blackhole\torrent".AsOsAgnostic(); _filePath = (@"c:\blackhole\torrent\" + _title + ".torrent").AsOsAgnostic(); Mocker.SetConstant(Mocker.Resolve()); Subject.Definition = new DownloadClientDefinition(); Subject.Definition.Settings = new TorrentBlackholeSettings { TorrentFolder = _blackholeFolder, WatchFolder = _completedDownloadFolder }; Mocker.GetMock() .Setup(c => c.OpenWriteStream(It.IsAny())) .Returns(() => new FileStream(GetTempFilePath(), FileMode.Create)); Mocker.GetMock() .Setup(c => c.GetHashFromTorrentFile(It.IsAny())) .Returns("myhash"); Mocker.GetMock().Setup(c => c.FilterPaths(It.IsAny(), It.IsAny>())) .Returns>((b, s) => s.ToList()); Mocker.GetMock().Setup(c => c.FilterFiles(It.IsAny(), It.IsAny>())) .Returns>((b, s) => s.ToList()); } protected void GivenFailedDownload() { Mocker.GetMock() .Setup(s => s.Get(It.IsAny())) .Throws(new WebException()); } protected void GivenCompletedItem() { var targetDir = Path.Combine(_completedDownloadFolder, _title); Mocker.GetMock() .Setup(c => c.GetDirectories(_completedDownloadFolder)) .Returns(new[] { targetDir }); Mocker.GetMock() .Setup(c => c.GetFiles(targetDir, SearchOption.AllDirectories)) .Returns(new[] { Path.Combine(targetDir, "somefile.flac") }); Mocker.GetMock() .Setup(c => c.GetFileSize(It.IsAny())) .Returns(1000000); } protected void GivenMagnetFilePath(string extension = ".magnet") { _magnetFilePath = Path.ChangeExtension(_filePath, extension); } protected override RemoteBook CreateRemoteBook() { var remoteBook = base.CreateRemoteBook(); var torrentInfo = new TorrentInfo(); torrentInfo.Title = remoteBook.Release.Title; torrentInfo.DownloadUrl = remoteBook.Release.DownloadUrl; torrentInfo.DownloadProtocol = remoteBook.Release.DownloadProtocol; torrentInfo.MagnetUrl = "magnet:?xt=urn:btih:755248817d32b00cc853e633ecdc48e4c21bff15&dn=Author.Book.FLAC.loseless-DEFiNE%5Brartv%5D&tr=http%3A%2F%2Ftracker.trackerfix.com%3A80%2Fannounce&tr=udp%3A%2F%2F9.rarbg.me%3A2710&tr=udp%3A%2F%2F9.rarbg.to%3A2710"; remoteBook.Release = torrentInfo; return remoteBook; } [Test] public void completed_download_should_have_required_properties() { Subject.ScanGracePeriod = TimeSpan.Zero; GivenCompletedItem(); var result = Subject.GetItems().Single(); VerifyCompleted(result); result.CanBeRemoved.Should().BeFalse(); result.CanMoveFiles.Should().BeFalse(); } [Test] public void partial_download_should_have_required_properties() { GivenCompletedItem(); var result = Subject.GetItems().Single(); VerifyPostprocessing(result); } [Test] public void should_return_category() { GivenCompletedItem(); var result = Subject.GetItems().Single(); // We must have a category or CDH won't pick it up. result.Category.Should().NotBeNullOrWhiteSpace(); } [Test] public void Download_should_download_file_if_it_doesnt_exist() { var remoteBook = CreateRemoteBook(); Subject.Download(remoteBook); Mocker.GetMock().Verify(c => c.Get(It.Is(v => v.Url.FullUri == _downloadUrl)), Times.Once()); Mocker.GetMock().Verify(c => c.OpenWriteStream(_filePath), Times.Once()); Mocker.GetMock().Verify(c => c.DownloadFile(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); } [Test] public void Download_should_save_magnet_if_enabled() { GivenMagnetFilePath(); Subject.Definition.Settings.As().SaveMagnetFiles = true; var remoteBook = CreateRemoteBook(); remoteBook.Release.DownloadUrl = null; Subject.Download(remoteBook); Mocker.GetMock().Verify(c => c.Get(It.Is(v => v.Url.FullUri == _downloadUrl)), Times.Never()); Mocker.GetMock().Verify(c => c.OpenWriteStream(_filePath), Times.Never()); Mocker.GetMock().Verify(c => c.OpenWriteStream(_magnetFilePath), Times.Once()); Mocker.GetMock().Verify(c => c.DownloadFile(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); } [Test] public void Download_should_save_magnet_using_specified_extension() { var magnetFileExtension = ".url"; GivenMagnetFilePath(magnetFileExtension); Subject.Definition.Settings.As().SaveMagnetFiles = true; Subject.Definition.Settings.As().MagnetFileExtension = magnetFileExtension; var remoteBook = CreateRemoteBook(); remoteBook.Release.DownloadUrl = null; Subject.Download(remoteBook); Mocker.GetMock().Verify(c => c.Get(It.Is(v => v.Url.FullUri == _downloadUrl)), Times.Never()); Mocker.GetMock().Verify(c => c.OpenWriteStream(_filePath), Times.Never()); Mocker.GetMock().Verify(c => c.OpenWriteStream(_magnetFilePath), Times.Once()); Mocker.GetMock().Verify(c => c.DownloadFile(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); } [Test] public void Download_should_not_save_magnet_if_disabled() { GivenMagnetFilePath(); var remoteBook = CreateRemoteBook(); remoteBook.Release.DownloadUrl = null; Assert.Throws(() => Subject.Download(remoteBook)); Mocker.GetMock().Verify(c => c.Get(It.Is(v => v.Url.FullUri == _downloadUrl)), Times.Never()); Mocker.GetMock().Verify(c => c.OpenWriteStream(_filePath), Times.Never()); Mocker.GetMock().Verify(c => c.OpenWriteStream(_magnetFilePath), Times.Never()); Mocker.GetMock().Verify(c => c.DownloadFile(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); } [Test] public void Download_should_prefer_torrent_over_magnet() { Subject.Definition.Settings.As().SaveMagnetFiles = true; var remoteBook = CreateRemoteBook(); Subject.Download(remoteBook); Mocker.GetMock().Verify(c => c.Get(It.Is(v => v.Url.FullUri == _downloadUrl)), Times.Once()); Mocker.GetMock().Verify(c => c.OpenWriteStream(_filePath), Times.Once()); Mocker.GetMock().Verify(c => c.OpenWriteStream(_magnetFilePath), Times.Never()); Mocker.GetMock().Verify(c => c.DownloadFile(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); } [Test] public void Download_should_replace_illegal_characters_in_title() { var illegalTitle = "Radiohead - Scotch Mist [2008/FLAC/Lossless]"; var expectedFilename = Path.Combine(_blackholeFolder, "Radiohead - Scotch Mist [2008+FLAC+Lossless]" + Path.GetExtension(_filePath)); var remoteBook = CreateRemoteBook(); remoteBook.Release.Title = illegalTitle; Subject.Download(remoteBook); Mocker.GetMock().Verify(c => c.Get(It.Is(v => v.Url.FullUri == _downloadUrl)), Times.Once()); Mocker.GetMock().Verify(c => c.OpenWriteStream(expectedFilename), Times.Once()); Mocker.GetMock().Verify(c => c.DownloadFile(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); } [Test] public void Download_should_throw_if_magnet_and_torrent_url_does_not_exist() { var remoteBook = CreateRemoteBook(); remoteBook.Release.DownloadUrl = null; Assert.Throws(() => Subject.Download(remoteBook)); } [Test] public void RemoveItem_should_delete_file() { GivenCompletedItem(); Mocker.GetMock() .Setup(c => c.FileExists(It.IsAny())) .Returns(true); Subject.RemoveItem("_Droned.S01E01.Pilot.1080p.WEB-DL-DRONE_0", true); Mocker.GetMock() .Verify(c => c.DeleteFile(It.IsAny()), Times.Once()); } [Test] public void RemoveItem_should_delete_directory() { GivenCompletedItem(); Mocker.GetMock() .Setup(c => c.FolderExists(It.IsAny())) .Returns(true); Subject.RemoveItem("_Droned.S01E01.Pilot.1080p.WEB-DL-DRONE_0", true); Mocker.GetMock() .Verify(c => c.DeleteFolder(It.IsAny(), true), Times.Once()); } [Test] public void RemoveItem_should_ignore_if_unknown_item() { Subject.RemoveItem("_Droned.S01E01.Pilot.1080p.WEB-DL-DRONE_0", true); Mocker.GetMock() .Verify(c => c.DeleteFile(It.IsAny()), Times.Never()); Mocker.GetMock() .Verify(c => c.DeleteFolder(It.IsAny(), true), Times.Never()); } [Test] public void RemoveItem_should_throw_if_deleteData_is_false() { GivenCompletedItem(); Assert.Throws(() => Subject.RemoveItem("_Droned.S01E01.Pilot.1080p.WEB-DL-DRONE_0", false)); Mocker.GetMock() .Verify(c => c.DeleteFile(It.IsAny()), Times.Never()); Mocker.GetMock() .Verify(c => c.DeleteFolder(It.IsAny(), true), Times.Never()); } [Test] public void should_return_status_with_outputdirs() { var result = Subject.GetStatus(); result.IsLocalhost.Should().BeTrue(); result.OutputRootFolders.Should().NotBeNull(); result.OutputRootFolders.First().Should().Be(_completedDownloadFolder); } [Test] public void should_return_null_hash() { var remoteBook = CreateRemoteBook(); Subject.Download(remoteBook).Should().BeNull(); } } }