using System; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.ServiceModel.Syndication; using System.Threading; using FizzWare.NBuilder; using FluentAssertions; using Moq; using NUnit.Framework; using NzbDrone.Common; using NzbDrone.Core.Model; using NzbDrone.Core.Providers; using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Indexer; using NzbDrone.Core.Repository; using NzbDrone.Core.Repository.Quality; using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.ProviderTests; using NzbDrone.Test.Common; namespace NzbDrone.Core.Test { [TestFixture] // ReSharper disable InconsistentNaming public class IndexerTests : CoreTest { [TestCase("nzbsrus.xml")] [TestCase("newzbin.xml")] [TestCase("nzbmatrix.xml")] [TestCase("newznab.xml")] [TestCase("wombles.xml")] [TestCase("filesharingtalk.xml")] [TestCase("nzbindex.xml")] [TestCase("nzbclub.xml")] public void parse_feed_xml(string fileName) { Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\" + fileName)); var fakeSettings = Builder.CreateNew().Build(); Mocker.GetMock() .Setup(c => c.GetSettings(It.IsAny())) .Returns(fakeSettings); var mockIndexer = Mocker.Resolve(); var parseResults = mockIndexer.FetchRss(); foreach (var episodeParseResult in parseResults) { var Uri = new Uri(episodeParseResult.NzbUrl); Uri.PathAndQuery.Should().NotContain("//"); } parseResults.Should().NotBeEmpty(); parseResults.Should().OnlyContain(s => s.Indexer == mockIndexer.Name); parseResults.Should().OnlyContain(s => !String.IsNullOrEmpty(s.OriginalString)); parseResults.Should().OnlyContain(s => s.Age >= 0); } private void WithConfiguredIndexers() { Mocker.GetMock().SetupGet(c => c.NzbMatrixApiKey).Returns("MockedConfigValue"); Mocker.GetMock().SetupGet(c => c.NzbMatrixUsername).Returns("MockedConfigValue"); Mocker.GetMock().SetupGet(c => c.NewzbinUsername).Returns("MockedConfigValue"); Mocker.GetMock().SetupGet(c => c.NewzbinPassword).Returns("MockedConfigValue"); Mocker.GetMock().SetupGet(c => c.NzbsOrgHash).Returns("MockedConfigValue"); Mocker.GetMock().SetupGet(c => c.NzbsOrgUId).Returns("MockedConfigValue"); Mocker.GetMock().SetupGet(c => c.NzbsrusHash).Returns("MockedConfigValue"); Mocker.GetMock().SetupGet(c => c.NzbsrusUId).Returns("MockedConfigValue"); Mocker.GetMock().SetupGet(c => c.FileSharingTalkUid).Returns("MockedConfigValue"); Mocker.GetMock().SetupGet(c => c.FileSharingTalkSecret).Returns("MockedConfigValue"); } [Test] public void newzbin_parses_languae() { WithConfiguredIndexers(); Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\newbin_none_english.xml")); var newzbin = Mocker.Resolve(); var parseResults = newzbin.FetchRss(); foreach (var episodeParseResult in parseResults) { var Uri = new Uri(episodeParseResult.NzbUrl); Uri.PathAndQuery.Should().NotContain("//"); } parseResults.Should().NotBeEmpty(); parseResults.Should().NotContain(e => e.Language == LanguageType.English); } [Test] public void newzbin_rss_fetch() { Mocker.Resolve(); var fakeSettings = Builder.CreateNew().Build(); Mocker.GetMock() .Setup(c => c.GetSettings(It.IsAny())) .Returns(fakeSettings); Mocker.GetMock() .SetupGet(c => c.NewzbinUsername) .Returns("nzbdrone"); Mocker.GetMock() .SetupGet(c => c.NewzbinPassword) .Returns("smartar39865"); var newzbinProvider = Mocker.Resolve(); var parseResults = newzbinProvider.FetchRss(); foreach (var episodeParseResult in parseResults) { var Uri = new Uri(episodeParseResult.NzbUrl); Uri.PathAndQuery.Should().NotContain("//"); } parseResults.Should().NotBeEmpty(); parseResults.Should().OnlyContain(s => s.Indexer == newzbinProvider.Name); parseResults.Should().OnlyContain(s => !String.IsNullOrEmpty(s.OriginalString)); Mark500Inconclusive(); ExceptionVerification.IgnoreWarns(); } [Test] public void custome_parser_partial_success() { const string title = "Adventure.Inc.S03E19.DVDRip.XviD-OSiTV"; const int season = 3; const int episode = 19; var quality = QualityTypes.DVD; const string summary = "My fake summary"; var fakeSettings = Builder.CreateNew().Build(); Mocker.GetMock() .Setup(c => c.GetSettings(It.IsAny())) .Returns(fakeSettings); var fakeRssItem = Builder.CreateNew() .With(c => c.Title = new TextSyndicationContent(title)) .With(c => c.Summary = new TextSyndicationContent(summary)) .Build(); var result = Mocker.Resolve().ParseFeed(fakeRssItem); Assert.IsNotNull(result); Assert.AreEqual(LanguageType.Finnish, result.Language); Assert.AreEqual(season, result.SeasonNumber); Assert.AreEqual(episode, result.EpisodeNumbers[0]); Assert.AreEqual(quality, result.Quality.Quality); } [TestCase("Adventure.Inc.DVDRip.XviD-OSiTV")] public void custome_parser_full_parse(string title) { const string summary = "My fake summary"; var fakeSettings = Builder.CreateNew().Build(); Mocker.GetMock() .Setup(c => c.GetSettings(It.IsAny())) .Returns(fakeSettings); var fakeRssItem = Builder.CreateNew() .With(c => c.Title = new TextSyndicationContent(title)) .With(c => c.Summary = new TextSyndicationContent(summary)) .Build(); var result = Mocker.Resolve().ParseFeed(fakeRssItem); Assert.IsNotNull(result); Assert.AreEqual(LanguageType.Finnish, result.Language); } [Test] public void downloadFeed() { Mocker.Resolve(); var fakeSettings = Builder.CreateNew().Build(); Mocker.GetMock() .Setup(c => c.GetSettings(It.IsAny())) .Returns(fakeSettings); Mocker.Resolve().FetchRss(); Mark500Inconclusive(); ExceptionVerification.IgnoreWarns(); } [TestCase("simpsons", 21, 23)] [TestCase("Hawaii Five-0 (2010)", 1, 1)] [TestCase("In plain Sight", 1, 11, Ignore = true)] public void newzbin_search_returns_valid_results(string title, int season, int episode) { Mocker.GetMock() .SetupGet(c => c.NewzbinUsername) .Returns("nzbdrone"); Mocker.GetMock() .SetupGet(c => c.NewzbinPassword) .Returns("smartar39865"); Mocker.Resolve(); var result = Mocker.Resolve().FetchEpisode(title, season, episode); Mark500Inconclusive(); result.Should().NotBeEmpty(); } [TestCase("simpsons", 21, 23)] [TestCase("The walking dead", 2, 10)] public void nzbmatrix_search_returns_valid_results(string title, int season, int episode) { WithConfiguredIndexers(); Mocker.Resolve(); var result = Mocker.Resolve().FetchEpisode(title, season, episode); Mark500Inconclusive(); result.Should().NotBeEmpty(); } [Test] public void nzbmatrix_multi_word_search_returns_valid_results() { WithConfiguredIndexers(); Mocker.Resolve(); var result = Mocker.Resolve().FetchEpisode("Blue Bloods", 1, 19); Mark500Inconclusive(); result.Should().NotBeEmpty(); } [TestCase("hawaii five-0 (2010)", "hawaii+five+0+2010")] [TestCase("this& that", "this+that")] [TestCase("this& that", "this+that")] [TestCase("grey's anatomy", "grey+s+anatomy")] public void get_query_title(string raw, string clean) { var mock = new Mock(); mock.CallBase = true; var result = mock.Object.GetQueryTitle(raw); result.Should().Be(clean); } [TestCase("hawaii five-0 (2010)", "hawaii+five+0+2010")] [TestCase("this& that", "this+that")] [TestCase("this& that", "this+that")] [TestCase("grey's anatomy", "greys+anatomy")] public void get_query_title_nzbmatrix_should_replace_apostrophe_with_empty_string(string raw, string clean) { var result = Mocker.Resolve().GetQueryTitle(raw); result.Should().Be(clean); } [Test] public void size_newzbin() { WithConfiguredIndexers(); Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\SizeParsing\\newzbin.xml")); //Act var parseResults = Mocker.Resolve().FetchRss(); parseResults.Should().HaveCount(1); parseResults[0].Size.Should().Be(1295620506); } [Test] public void size_nzbmatrix() { WithConfiguredIndexers(); Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\SizeParsing\\nzbmatrix.xml")); //Act var parseResults = Mocker.Resolve().FetchRss(); parseResults.Should().HaveCount(1); parseResults[0].Size.Should().Be(1331439862); } [Test] public void size_nzbsrus() { WithConfiguredIndexers(); Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\SizeParsing\\nzbsrus.xml")); //Act var parseResults = Mocker.Resolve().FetchRss(); parseResults.Should().HaveCount(1); parseResults[0].Size.Should().Be(1793148846); } [Test] public void size_newznab() { WithConfiguredIndexers(); var newznabDefs = Builder.CreateListOfSize(1) .All() .With(n => n.ApiKey = String.Empty) .Build(); Mocker.GetMock().Setup(s => s.Enabled()).Returns(newznabDefs.ToList()); Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\SizeParsing\\newznab.xml")); //Act var parseResults = Mocker.Resolve().FetchRss(); parseResults[0].Size.Should().Be(1183105773); } [Test] public void size_nzbindex() { WithConfiguredIndexers(); Mocker.GetMock() .Setup(h => h.DownloadStream("http://www.nzbindex.nl/rss/alt.binaries.teevee/?sort=agedesc&minsize=100&complete=1&max=50&more=1&q=%23a.b.teevee%40EFNet", It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\SizeParsing\\nzbindex.xml")); Mocker.GetMock() .Setup(h => h.DownloadStream("http://www.nzbindex.nl/rss/alt.binaries.hdtv/?sort=agedesc&minsize=100&complete=1&max=50&more=1&q=", It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\SizeParsing\\nzbindex.xml")); //Act var parseResults = Mocker.Resolve().FetchRss(); parseResults[0].Size.Should().Be(587328389); } [Test] public void size_nzbclub() { WithConfiguredIndexers(); Mocker.GetMock() .Setup(h => h.DownloadStream("http://www.nzbclub.com/nzbfeed.aspx?ig=2&gid=102952&st=1&ns=1&q=%23a.b.teevee%40EFNet", It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\SizeParsing\\nzbclub.xml")); Mocker.GetMock() .Setup(h => h.DownloadStream("http://www.nzbclub.com/nzbfeed.aspx?ig=2&gid=5542&st=1&ns=1&q=", It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\SizeParsing\\nzbclub.xml")); //Act var parseResults = Mocker.Resolve().FetchRss(); parseResults.Should().HaveCount(2); parseResults[0].Size.Should().Be(2652142305); } [Test] public void Server_Unavailable_503_should_not_log_exception() { Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Throws(new WebException("503")); Mocker.Resolve().FetchRss(); ExceptionVerification.ExpectedErrors(0); ExceptionVerification.ExpectedWarns(1); } [Test] public void none_503_server_error_should_still_log_error() { WithConfiguredIndexers(); Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Throws(new WebException("some other server error")); Mocker.Resolve().FetchRss(); ExceptionVerification.ExpectedErrors(1); ExceptionVerification.ExpectedWarns(0); } [Test] public void indexer_that_isnt_configured_shouldnt_make_an_http_call() { Mocker.Resolve().FetchRss(); Mocker.GetMock() .Verify(c => c.DownloadFile(It.IsAny(), It.IsAny()), Times.Never()); ExceptionVerification.ExpectedWarns(1); } [Test] public void newznab_link_should_be_link_to_nzb_not_details() { Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\newznab.xml")); var fakeSettings = Builder.CreateNew().Build(); Mocker.GetMock() .Setup(c => c.GetSettings(It.IsAny())) .Returns(fakeSettings); var mockIndexer = Mocker.Resolve(); var parseResults = mockIndexer.FetchRss(); parseResults.Should().NotBeEmpty(); parseResults.Should().OnlyContain(s => s.NzbUrl.Contains("getnzb")); parseResults.Should().NotContain(s => s.NzbUrl.Contains("details")); } [Test] public void nzbmatrix_should_use_age_from_custom() { WithConfiguredIndexers(); var expectedAge = DateTime.Now.Subtract(new DateTime(2011, 4, 25, 15, 6, 58)).Days; Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\SizeParsing\\nzbmatrix.xml")); //Act var parseResults = Mocker.Resolve().FetchRss(); parseResults.Should().HaveCount(1); parseResults[0].Age.Should().Be(expectedAge); } private static void Mark500Inconclusive() { ExceptionVerification.MarkInconclusive(typeof(WebException)); ExceptionVerification.MarkInconclusive("System.Net.WebException"); ExceptionVerification.MarkInconclusive("(503) Server Unavailable."); ExceptionVerification.MarkInconclusive("(500) Internal Server Error."); } [TestCase("wombles.xml", "de-de")] public void dateTime_should_parse_when_using_other_cultures(string fileName, string culture) { var currentCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = new CultureInfo(culture); Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\" + fileName)); var fakeSettings = Builder.CreateNew().Build(); Mocker.GetMock() .Setup(c => c.GetSettings(It.IsAny())) .Returns(fakeSettings); var mockIndexer = Mocker.Resolve(); var parseResults = mockIndexer.FetchRss(); foreach (var episodeParseResult in parseResults) { var Uri = new Uri(episodeParseResult.NzbUrl); Uri.PathAndQuery.Should().NotContain("//"); } parseResults.Should().NotBeEmpty(); parseResults.Should().OnlyContain(s => s.Indexer == mockIndexer.Name); parseResults.Should().OnlyContain(s => !String.IsNullOrEmpty(s.OriginalString)); parseResults.Should().OnlyContain(s => s.Age >= 0); Thread.CurrentThread.CurrentCulture = currentCulture; } [Test] public void NzbsRus_NzbInfoUrl_should_contain_information_string() { WithConfiguredIndexers(); const string fileName = "nzbsrus.xml"; const string expectedString = "nzbdetails"; Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\" + fileName)); var parseResults = Mocker.Resolve().FetchRss(); foreach (var episodeParseResult in parseResults) { episodeParseResult.NzbInfoUrl.Should().Contain(expectedString); } } [Test] public void Newzbin_NzbInfoUrl_should_contain_information_string() { WithConfiguredIndexers(); const string fileName = "newzbin.xml"; const string expectedString = "browse"; Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\" + fileName)); var parseResults = Mocker.Resolve().FetchRss(); foreach (var episodeParseResult in parseResults) { episodeParseResult.NzbInfoUrl.Should().Contain(expectedString); } } [Test] public void NzbMatrix_NzbInfoUrl_should_contain_information_string() { WithConfiguredIndexers(); const string fileName = "nzbmatrix.xml"; const string expectedString = "nzb-details"; Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\" + fileName)); var parseResults = Mocker.Resolve().FetchRss(); foreach (var episodeParseResult in parseResults) { episodeParseResult.NzbInfoUrl.Should().Contain(expectedString); } } [Test] public void Newznab_NzbInfoUrl_should_contain_information_string() { WithConfiguredIndexers(); const string fileName = "newznab.xml"; const string expectedString = "/details/"; var newznabDefs = Builder.CreateListOfSize(1) .All() .With(n => n.ApiKey = String.Empty) .Build(); Mocker.GetMock().Setup(s => s.Enabled()).Returns(newznabDefs.ToList()); Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\" + fileName)); var parseResults = Mocker.Resolve().FetchRss(); foreach (var episodeParseResult in parseResults) { episodeParseResult.NzbInfoUrl.Should().Contain(expectedString); } } [Test] public void Wombles_NzbInfoUrl_should_contain_information_string() { WithConfiguredIndexers(); const string fileName = "wombles.xml"; const string expectedString = "nzbdetails"; Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\" + fileName)); var parseResults = Mocker.Resolve().FetchRss(); foreach (var episodeParseResult in parseResults) { episodeParseResult.NzbInfoUrl.Should().BeNull(); } } [Test] public void FileSharingTalk_NzbInfoUrl_should_contain_information_string() { WithConfiguredIndexers(); const string fileName = "filesharingtalk.xml"; const string expectedString = "/nzbs/tv"; Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\" + fileName)); var parseResults = Mocker.Resolve().FetchRss(); foreach (var episodeParseResult in parseResults) { episodeParseResult.NzbInfoUrl.Should().Contain(expectedString); } } [Test] public void NzbIndex_NzbInfoUrl_should_contain_information_string() { WithConfiguredIndexers(); const string fileName = "nzbindex.xml"; const string expectedString = "release"; Mocker.GetMock() .Setup(h => h.DownloadStream("http://www.nzbindex.nl/rss/alt.binaries.teevee/?sort=agedesc&minsize=100&complete=1&max=50&more=1&q=%23a.b.teevee%40EFNet", It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\nzbindex.xml")); Mocker.GetMock() .Setup(h => h.DownloadStream("http://www.nzbindex.nl/rss/alt.binaries.hdtv/?sort=agedesc&minsize=100&complete=1&max=50&more=1&q=", It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\nzbindex.xml")); var parseResults = Mocker.Resolve().FetchRss(); foreach (var episodeParseResult in parseResults) { episodeParseResult.NzbInfoUrl.Should().Contain(expectedString); } } [Test] public void NzbClub_NzbInfoUrl_should_contain_information_string() { WithConfiguredIndexers(); const string fileName = "nzbclub.xml"; const string expectedString = "nzb_view"; Mocker.GetMock() .Setup(h => h.DownloadStream("http://www.nzbclub.com/nzbfeed.aspx?ig=2&gid=102952&st=1&ns=1&q=%23a.b.teevee%40EFNet", It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\" + fileName)); Mocker.GetMock() .Setup(h => h.DownloadStream("http://www.nzbclub.com/nzbfeed.aspx?ig=2&gid=5542&st=1&ns=1&q=", It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\" + fileName)); var parseResults = Mocker.Resolve().FetchRss(); foreach (var episodeParseResult in parseResults) { episodeParseResult.NzbInfoUrl.Should().Contain(expectedString); } } [Test] public void releaseGroup_should_use_nfo_filename_for_newzbin() { WithConfiguredIndexers(); Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) .Returns(File.OpenRead(".\\Files\\Rss\\SizeParsing\\newzbin.xml")); //Act var parseResults = Mocker.Resolve().FetchRss(); parseResults.Should().HaveCount(1); parseResults[0].ReleaseGroup.Should().Be("tvp"); } [TestCase("30 Rock", "30%20Rock")] [TestCase("The Office (US)", "Office%20US")] [TestCase("Revenge", "Revenge")] [TestCase(" Top Gear ", "Top%20Gear")] [TestCase("Breaking Bad", "Breaking%20Bad")] [TestCase("Top Chef (US)", "Top%20Chef%20US")] [TestCase("Castle (2009)", "Castle%202009")] public void newznab_GetQueryTitle_should_return_expected_result(string seriesTitle, string expected) { Mocker.Resolve().GetQueryTitle(seriesTitle).Should().Be(expected); } } }