mirror of
https://github.com/Radarr/Radarr.git
synced 2026-03-28 18:05:41 -04:00
Compare commits
155 Commits
v2.0.0.300
...
v2.0.0.324
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7e368d27b | ||
|
|
c72f9c8f27 | ||
|
|
83ff02545e | ||
|
|
2d25c74758 | ||
|
|
4d924688d8 | ||
|
|
3b805c4591 | ||
|
|
e5278a0243 | ||
|
|
7c246abc88 | ||
|
|
475f4244c4 | ||
|
|
f57dea7f1f | ||
|
|
f1a5261e0a | ||
|
|
fe5cb9503c | ||
|
|
944a775625 | ||
|
|
c8c17bce7e | ||
|
|
366e3ed0be | ||
|
|
cef6eb7509 | ||
|
|
f88e2e2b79 | ||
|
|
57bcc9f4c1 | ||
|
|
69dd1c6ec4 | ||
|
|
761a106fa9 | ||
|
|
5cd2d71e6f | ||
|
|
96578ca59b | ||
|
|
213f905767 | ||
|
|
9d980a8ac7 | ||
|
|
c4e1a732dd | ||
|
|
9f73b2b7f0 | ||
|
|
149c149094 | ||
|
|
ee224cb422 | ||
|
|
335be1c85d | ||
|
|
a79fc94a54 | ||
|
|
c3acfe34fe | ||
|
|
6e7a2af86b | ||
|
|
cce280d260 | ||
|
|
852f97012f | ||
|
|
f221b00795 | ||
|
|
429298c68c | ||
|
|
af060d73cc | ||
|
|
e98a174884 | ||
|
|
92a23d0f8b | ||
|
|
d5ba11bd51 | ||
|
|
a8aac36379 | ||
|
|
23c6da4746 | ||
|
|
cf9391a7a3 | ||
|
|
d0bf539a73 | ||
|
|
95bd82778f | ||
|
|
b73413f189 | ||
|
|
df4604057e | ||
|
|
1e2ba691ed | ||
|
|
6abda8adef | ||
|
|
84128482f4 | ||
|
|
a184021621 | ||
|
|
c4f8e44f55 | ||
|
|
b359e1c175 | ||
|
|
6dd22e7dcb | ||
|
|
29ca1bc9da | ||
|
|
bc03ad2a18 | ||
|
|
14f49489a7 | ||
|
|
4356da039f | ||
|
|
587aff602a | ||
|
|
1275d8098d | ||
|
|
0c6ca6971d | ||
|
|
f5fde97f68 | ||
|
|
50dc4c4f3d | ||
|
|
c08d8252ff | ||
|
|
2a83088045 | ||
|
|
4ca8178ca8 | ||
|
|
bb48491eb2 | ||
|
|
0534fb4330 | ||
|
|
8b7eedf6f9 | ||
|
|
6ab629ea98 | ||
|
|
97cbdfdc5c | ||
|
|
25c77711cd | ||
|
|
2e6cf2b7f6 | ||
|
|
6592310f2b | ||
|
|
918fcac2aa | ||
|
|
4b7ee3cb9e | ||
|
|
27246de623 | ||
|
|
b1a0e759ef | ||
|
|
f90fdef50d | ||
|
|
702b4429ac | ||
|
|
4eff8d88d1 | ||
|
|
235a986679 | ||
|
|
c3e0dbc173 | ||
|
|
e296d94417 | ||
|
|
0e865fff8c | ||
|
|
9a629c2fc6 | ||
|
|
ecd941a6e5 | ||
|
|
2feb583e45 | ||
|
|
23daae05cc | ||
|
|
b4e8a39c2c | ||
|
|
2f7e3c1c3c | ||
|
|
8a0e873eb5 | ||
|
|
10214bff42 | ||
|
|
1fc99fd24e | ||
|
|
e40508e5e9 | ||
|
|
65f1dbde00 | ||
|
|
4c9f13cb26 | ||
|
|
f831dbd789 | ||
|
|
f18ad21b48 | ||
|
|
61ae7dc189 | ||
|
|
e304a615d0 | ||
|
|
c12f16b6d3 | ||
|
|
c43296ffe9 | ||
|
|
ab6233dd3f | ||
|
|
2a4fd2bbde | ||
|
|
c3d15015fe | ||
|
|
f30e7bc701 | ||
|
|
ee87537848 | ||
|
|
d4532c3856 | ||
|
|
20e40f73b3 | ||
|
|
923488bc02 | ||
|
|
b62d36bdbe | ||
|
|
62f4fc5e58 | ||
|
|
cfefed34fc | ||
|
|
c58d607349 | ||
|
|
f13a4b5aa5 | ||
|
|
9cf575c096 | ||
|
|
2c52ac1a7b | ||
|
|
7e0c833ad0 | ||
|
|
7f38617d76 | ||
|
|
8aa6969aee | ||
|
|
0adea0ded6 | ||
|
|
ccfd66260d | ||
|
|
a6d2283be8 | ||
|
|
b92cc6fb15 | ||
|
|
f2ec02876b | ||
|
|
7378a98e07 | ||
|
|
42a3ff2625 | ||
|
|
4448e87e28 | ||
|
|
90b047f0d4 | ||
|
|
adfaa00ce1 | ||
|
|
755a42ea45 | ||
|
|
210524b51a | ||
|
|
a1a91878ad | ||
|
|
216286db5e | ||
|
|
061c40c8f4 | ||
|
|
15eeb19cd5 | ||
|
|
93c6047cd5 | ||
|
|
db4746bef7 | ||
|
|
971e159fa4 | ||
|
|
a4deea2333 | ||
|
|
6114952012 | ||
|
|
fcc1439754 | ||
|
|
06a2cb0de4 | ||
|
|
9dd66879a2 | ||
|
|
5d03c94b26 | ||
|
|
679455713e | ||
|
|
9aeda7aaba | ||
|
|
ca8e16a5be | ||
|
|
52ec1cf1b1 | ||
|
|
1efb7446c9 | ||
|
|
c5f2c2823e | ||
|
|
beb4aee4c9 | ||
|
|
638e3ca898 | ||
|
|
dea58ed663 |
@@ -114,8 +114,8 @@ Function PackageMono()
|
||||
get-childitem $outputFolderMono -File -Filter sqlite3.* -Recurse | foreach ($_) {remove-item $_.fullname}
|
||||
get-childitem $outputFolderMono -File -Filter MediaInfo.* -Recurse | foreach ($_) {remove-item $_.fullname}
|
||||
|
||||
Write-Host "Adding MediaInfoDotNet.dll.config (for dllmap)"
|
||||
Copy-Item "$sourceFolder\MediaInfoDotNet.dll.config" $outputFolderMono
|
||||
Write-Host "Adding NzbDrone.Core.dll.config (for dllmap)"
|
||||
Copy-Item "$sourceFolder\NzbDrone.Core\NzbDrone.Core.dll.config" $outputFolderMono
|
||||
|
||||
Write-Host Renaming NzbDrone.Console.exe to NzbDrone.exe
|
||||
Get-ChildItem $outputFolderMono -File -Filter "NzbDrone.exe*" -Recurse | foreach ($_) {remove-item $_.fullname}
|
||||
@@ -212,8 +212,8 @@ Function PackageTests()
|
||||
|
||||
CleanFolder $testPackageFolder $true
|
||||
|
||||
Write-Host "Adding MediaInfoDotNet.dll.config (for dllmap)"
|
||||
Copy-Item "$sourceFolder\MediaInfoDotNet.dll.config" -Destination $testPackageFolder -Force
|
||||
Write-Host "Adding NzbDrone.Core.dll.config (for dllmap)"
|
||||
Copy-Item "$sourceFolder\NzbDrone.Core\NzbDrone.Core.dll.config" -Destination $testPackageFolder -Force
|
||||
|
||||
Write-Host "##teamcity[progressFinish 'Creating Test Package']"
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ gulp.task('copyJs', function () {
|
||||
return gulp.src(
|
||||
[
|
||||
paths.src.root + "polyfills.js",
|
||||
paths.src.root + "JsLibraries\\handlebars.runtime.js",
|
||||
paths.src.root + "JsLibraries/handlebars.runtime.js",
|
||||
])
|
||||
.pipe(cache('copyJs'))
|
||||
.pipe(print())
|
||||
|
||||
@@ -15,6 +15,7 @@ gulp.task('less', function () {
|
||||
paths.src.root + 'AddSeries/addSeries.less',
|
||||
paths.src.root + 'Calendar/calendar.less',
|
||||
paths.src.root + 'Cells/cells.less',
|
||||
paths.src.root + 'ManualImport/manualimport.less',
|
||||
paths.src.root + 'Settings/settings.less',
|
||||
paths.src.root + 'System/Logs/logs.less',
|
||||
paths.src.root + 'System/Update/update.less',
|
||||
|
||||
@@ -1 +1 @@
|
||||
require('./gulp/gulpfile.js');
|
||||
require('./gulp/gulpFile.js');
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
DIR=$(cd "$(dirname "$0")"; pwd)
|
||||
|
||||
#change these values to match your app
|
||||
EXE_PATH="$DIR/nzbdrone.exe"
|
||||
EXE_PATH="$DIR/NzbDrone.exe"
|
||||
APPNAME="Sonarr"
|
||||
|
||||
#set up environment
|
||||
|
||||
4
src/LogentriesNLog/packages.config
Normal file
4
src/LogentriesNLog/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="NLog" version="2.1.0" targetFramework="net40" />
|
||||
</packages>
|
||||
@@ -144,7 +144,7 @@
|
||||
<PreBuildEvent>
|
||||
</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<dllmap os="osx" dll="MediaInfo.dll" target="libmediainfo.0.dylib"/>
|
||||
<dllmap os="linux" dll="MediaInfo.dll" target="libmediainfo.so.0" />
|
||||
<dllmap os="freebsd" dll="MediaInfo.dll" target="libmediainfo.so.0" />
|
||||
<dllmap os="solaris" dll="MediaInfo.dll" target="libmediainfo.so.0.0.0" />
|
||||
</configuration>
|
||||
@@ -116,14 +116,12 @@ namespace NzbDrone.Api.Test.MappingTests
|
||||
profileResource.InjectTo<Profile>();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_map_tracked_command()
|
||||
{
|
||||
var profileResource = new ApplicationUpdateCommand();
|
||||
profileResource.InjectTo<CommandResource>();
|
||||
var commandResource = new CommandModel { Body = new ApplicationUpdateCommand() };
|
||||
commandResource.InjectTo<CommandResource>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
<HintPath>..\packages\Moq.4.0.10827\lib\NET40\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Omu.ValueInjecter">
|
||||
<HintPath>..\packages\valueinjecter.2.3.3\lib\net35\Omu.ValueInjecter.dll</HintPath>
|
||||
<HintPath>..\packages\ValueInjecter.2.3.3\lib\net35\Omu.ValueInjecter.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -104,7 +104,7 @@
|
||||
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
@@ -112,4 +112,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
<package id="Moq" version="4.0.10827" />
|
||||
<package id="NBuilder" version="3.0.1.1" targetFramework="net40" />
|
||||
<package id="NUnit" version="2.6.3" targetFramework="net40" />
|
||||
<package id="valueinjecter" version="2.3.3" targetFramework="net40" />
|
||||
</packages>
|
||||
<package id="ValueInjecter" version="2.3.3" targetFramework="net40" />
|
||||
</packages>
|
||||
|
||||
@@ -74,8 +74,8 @@ namespace NzbDrone.Api.Authentication
|
||||
{
|
||||
if (context.Request.IsApiRequest())
|
||||
{
|
||||
if ((context.Response.StatusCode == HttpStatusCode.SeeOther &&
|
||||
context.Response.ContentType.Equals("text/html", StringComparison.InvariantCultureIgnoreCase)) ||
|
||||
if ((context.Response.StatusCode == HttpStatusCode.SeeOther &&
|
||||
context.Response.Headers["Location"].StartsWith("/login", StringComparison.InvariantCultureIgnoreCase)) ||
|
||||
context.Response.StatusCode == HttpStatusCode.Unauthorized)
|
||||
{
|
||||
context.Response = new { Error = "Unauthorized" }.AsResponse(HttpStatusCode.Unauthorized);
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Api.Series;
|
||||
using NzbDrone.Core.Indexers;
|
||||
|
||||
namespace NzbDrone.Api.Blacklist
|
||||
{
|
||||
@@ -13,6 +14,9 @@ namespace NzbDrone.Api.Blacklist
|
||||
public string SourceTitle { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public DownloadProtocol Protocol { get; set; }
|
||||
public string Indexer { get; set; }
|
||||
public string Message { get; set; }
|
||||
|
||||
public SeriesResource Series { get; set; }
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace NzbDrone.Api.Calendar
|
||||
if (queryStart.HasValue) start = DateTime.Parse(queryStart.Value);
|
||||
if (queryEnd.HasValue) end = DateTime.Parse(queryEnd.Value);
|
||||
|
||||
var episodes = _episodeService.EpisodesBetweenDates(start, end);
|
||||
var episodes = _episodeService.EpisodesBetweenDates(start, end, false);
|
||||
var icalCalendar = new iCalendar();
|
||||
|
||||
foreach (var episode in episodes.OrderBy(v => v.AirDateUtc.Value))
|
||||
|
||||
@@ -23,14 +23,17 @@ namespace NzbDrone.Api.Calendar
|
||||
{
|
||||
var start = DateTime.Today;
|
||||
var end = DateTime.Today.AddDays(2);
|
||||
var includeUnmonitored = false;
|
||||
|
||||
var queryStart = Request.Query.Start;
|
||||
var queryEnd = Request.Query.End;
|
||||
var queryIncludeUnmonitored = Request.Query.Unmonitored;
|
||||
|
||||
if (queryStart.HasValue) start = DateTime.Parse(queryStart.Value);
|
||||
if (queryEnd.HasValue) end = DateTime.Parse(queryEnd.Value);
|
||||
if (queryIncludeUnmonitored.HasValue) includeUnmonitored = Convert.ToBoolean(queryIncludeUnmonitored.Value);
|
||||
|
||||
var resources = ToListResource(() => _episodeService.EpisodesBetweenDates(start, end));
|
||||
var resources = ToListResource(() => _episodeService.EpisodesBetweenDates(start, end, includeUnmonitored));
|
||||
|
||||
return resources.OrderBy(e => e.AirDateUtc).ToList();
|
||||
}
|
||||
|
||||
@@ -53,11 +53,9 @@ namespace NzbDrone.Api.ClientSchema
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
return result.OrderBy(r => r.Order).ToList();
|
||||
}
|
||||
|
||||
|
||||
public static object ReadFormSchema(List<Field> fields, Type targetType, object defaults = null)
|
||||
{
|
||||
Ensure.That(targetType, () => targetType).IsNotNull();
|
||||
|
||||
@@ -4,10 +4,9 @@ using System.Linq;
|
||||
using NzbDrone.Api.Extensions;
|
||||
using NzbDrone.Api.Mapping;
|
||||
using NzbDrone.Api.Validation;
|
||||
using NzbDrone.Common.Composition;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Commands.Tracking;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.ProgressMessaging;
|
||||
using NzbDrone.SignalR;
|
||||
@@ -15,58 +14,55 @@ using NzbDrone.SignalR;
|
||||
|
||||
namespace NzbDrone.Api.Commands
|
||||
{
|
||||
public class CommandModule : NzbDroneRestModuleWithSignalR<CommandResource, Command>, IHandle<CommandUpdatedEvent>
|
||||
public class CommandModule : NzbDroneRestModuleWithSignalR<CommandResource, CommandModel>, IHandle<CommandUpdatedEvent>
|
||||
{
|
||||
private readonly ICommandExecutor _commandExecutor;
|
||||
private readonly IContainer _container;
|
||||
private readonly ITrackCommands _trackCommands;
|
||||
private readonly IManageCommandQueue _commandQueueManager;
|
||||
private readonly IServiceFactory _serviceFactory;
|
||||
|
||||
public CommandModule(ICommandExecutor commandExecutor,
|
||||
public CommandModule(IManageCommandQueue commandQueueManager,
|
||||
IBroadcastSignalRMessage signalRBroadcaster,
|
||||
IContainer container,
|
||||
ITrackCommands trackCommands)
|
||||
IServiceFactory serviceFactory)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_commandExecutor = commandExecutor;
|
||||
_container = container;
|
||||
_trackCommands = trackCommands;
|
||||
_commandQueueManager = commandQueueManager;
|
||||
_serviceFactory = serviceFactory;
|
||||
|
||||
GetResourceById = GetCommand;
|
||||
CreateResource = StartCommand;
|
||||
GetResourceAll = GetAllCommands;
|
||||
GetResourceAll = GetStartedCommands;
|
||||
|
||||
PostValidator.RuleFor(c => c.Name).NotBlank();
|
||||
}
|
||||
|
||||
private CommandResource GetCommand(int id)
|
||||
{
|
||||
return _trackCommands.GetById(id).InjectTo<CommandResource>();
|
||||
return _commandQueueManager.Get(id).InjectTo<CommandResource>();
|
||||
}
|
||||
|
||||
private int StartCommand(CommandResource commandResource)
|
||||
{
|
||||
var commandType =
|
||||
_container.GetImplementations(typeof(Command))
|
||||
.Single(c => c.Name.Replace("Command", "")
|
||||
.Equals(commandResource.Name, StringComparison.InvariantCultureIgnoreCase));
|
||||
_serviceFactory.GetImplementations(typeof (Command))
|
||||
.Single(c => c.Name.Replace("Command", "")
|
||||
.Equals(commandResource.Name, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
dynamic command = Request.Body.FromJson(commandType);
|
||||
command.Manual = true;
|
||||
command.Trigger = CommandTrigger.Manual;
|
||||
|
||||
var trackedCommand = (Command)_commandExecutor.PublishCommandAsync(command);
|
||||
var trackedCommand = _commandQueueManager.Push(command, CommandPriority.Normal, CommandTrigger.Manual);
|
||||
return trackedCommand.Id;
|
||||
}
|
||||
|
||||
private List<CommandResource> GetAllCommands()
|
||||
private List<CommandResource> GetStartedCommands()
|
||||
{
|
||||
return ToListResource(_trackCommands.RunningCommands);
|
||||
return ToListResource(_commandQueueManager.GetStarted());
|
||||
}
|
||||
|
||||
public void Handle(CommandUpdatedEvent message)
|
||||
{
|
||||
if (message.Command.SendUpdatesToClient)
|
||||
if (message.Command.Body.SendUpdatesToClient)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, message.Command.Id);
|
||||
BroadcastResourceChange(ModelAction.Updated, message.Command.InjectTo<CommandResource>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Core.Messaging.Commands.Tracking;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Api.Commands
|
||||
{
|
||||
@@ -8,11 +9,75 @@ namespace NzbDrone.Api.Commands
|
||||
{
|
||||
public String Name { get; set; }
|
||||
public String Message { get; set; }
|
||||
public DateTime StartedOn { get; set; }
|
||||
public DateTime StateChangeTime { get; set; }
|
||||
public Boolean SendUpdatesToClient { get; set; }
|
||||
public CommandStatus State { get; set; }
|
||||
public Command Body { get; set; }
|
||||
public CommandPriority Priority { get; set; }
|
||||
public CommandStatus Status { get; set; }
|
||||
public DateTime Queued { get; set; }
|
||||
public DateTime? Started { get; set; }
|
||||
public DateTime? Ended { get; set; }
|
||||
public TimeSpan? Duration { get; set; }
|
||||
public string Exception { get; set; }
|
||||
public CommandTrigger Trigger { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public string CompletionMessage { get; set; }
|
||||
|
||||
//Legacy
|
||||
public CommandStatus State
|
||||
{
|
||||
get
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
set { }
|
||||
}
|
||||
|
||||
public Boolean Manual
|
||||
{
|
||||
get
|
||||
{
|
||||
return Trigger == CommandTrigger.Manual;
|
||||
}
|
||||
|
||||
set { }
|
||||
}
|
||||
|
||||
public DateTime StartedOn
|
||||
{
|
||||
get
|
||||
{
|
||||
return Queued;
|
||||
}
|
||||
|
||||
set { }
|
||||
}
|
||||
|
||||
public DateTime? StateChangeTime
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (Started.HasValue) return Started.Value;
|
||||
|
||||
return Ended;
|
||||
}
|
||||
|
||||
set { }
|
||||
}
|
||||
|
||||
public Boolean SendUpdatesToClient
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Body != null) return Body.SendUpdatesToClient;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
set { }
|
||||
}
|
||||
|
||||
public DateTime? LastExecutionTime { get; set; }
|
||||
public Boolean Manual { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,16 +7,19 @@ namespace NzbDrone.Api.Config
|
||||
{
|
||||
public class DownloadClientConfigModule : NzbDroneConfigModule<DownloadClientConfigResource>
|
||||
{
|
||||
public DownloadClientConfigModule(IConfigService configService, RootFolderValidator rootFolderValidator, PathExistsValidator pathExistsValidator)
|
||||
public DownloadClientConfigModule(IConfigService configService,
|
||||
RootFolderValidator rootFolderValidator,
|
||||
PathExistsValidator pathExistsValidator,
|
||||
MappedNetworkDriveValidator mappedNetworkDriveValidator)
|
||||
: base(configService)
|
||||
{
|
||||
SharedValidator.RuleFor(c => c.DownloadedEpisodesFolder)
|
||||
.Cascade(CascadeMode.StopOnFirstFailure)
|
||||
.IsValidPath()
|
||||
.SetValidator(rootFolderValidator)
|
||||
.SetValidator(mappedNetworkDriveValidator)
|
||||
.SetValidator(pathExistsValidator)
|
||||
.When(c => !String.IsNullOrWhiteSpace(c.DownloadedEpisodesFolder));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,5 +14,7 @@ namespace NzbDrone.Api.Config
|
||||
public String LongDateFormat { get; set; }
|
||||
public String TimeFormat { get; set; }
|
||||
public Boolean ShowRelativeDates { get; set; }
|
||||
|
||||
public Boolean EnableColorImpairedMode { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ namespace NzbDrone.Api.Episodes
|
||||
public Nullable<Int32> SceneAbsoluteEpisodeNumber { get; set; }
|
||||
public Nullable<Int32> SceneEpisodeNumber { get; set; }
|
||||
public Nullable<Int32> SceneSeasonNumber { get; set; }
|
||||
public Int32 TvDbEpisodeId { get; set; }
|
||||
public DateTime? EndTime { get; set; }
|
||||
public DateTime? GrabDate { get; set; }
|
||||
public String SeriesTitle { get; set; }
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Nancy;
|
||||
using NzbDrone.Api.Extensions;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
|
||||
namespace NzbDrone.Api.FileSystem
|
||||
{
|
||||
public class FileSystemModule : NzbDroneApiModule
|
||||
{
|
||||
private readonly IFileSystemLookupService _fileSystemLookupService;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IDiskScanService _diskScanService;
|
||||
|
||||
public FileSystemModule(IFileSystemLookupService fileSystemLookupService)
|
||||
public FileSystemModule(IFileSystemLookupService fileSystemLookupService,
|
||||
IDiskProvider diskProvider,
|
||||
IDiskScanService diskScanService)
|
||||
: base("/filesystem")
|
||||
{
|
||||
_fileSystemLookupService = fileSystemLookupService;
|
||||
_diskProvider = diskProvider;
|
||||
_diskScanService = diskScanService;
|
||||
Get["/"] = x => GetContents();
|
||||
Get["/type"] = x => GetEntityType();
|
||||
Get["/mediafiles"] = x => GetMediaFiles();
|
||||
}
|
||||
|
||||
private Response GetContents()
|
||||
@@ -29,5 +41,36 @@ namespace NzbDrone.Api.FileSystem
|
||||
|
||||
return _fileSystemLookupService.LookupContents((string)pathQuery.Value, includeFiles).AsResponse();
|
||||
}
|
||||
|
||||
private Response GetEntityType()
|
||||
{
|
||||
var pathQuery = Request.Query.path;
|
||||
var path = (string)pathQuery.Value;
|
||||
|
||||
if (_diskProvider.FileExists(path))
|
||||
{
|
||||
return new { type = "file" }.AsResponse();
|
||||
}
|
||||
|
||||
//Return folder even if it doesn't exist on disk to avoid leaking anything from the UI about the underlying system
|
||||
return new { type = "folder" }.AsResponse();
|
||||
}
|
||||
|
||||
private Response GetMediaFiles()
|
||||
{
|
||||
var pathQuery = Request.Query.path;
|
||||
var path = (string)pathQuery.Value;
|
||||
|
||||
if (!_diskProvider.FolderExists(path))
|
||||
{
|
||||
return new string[0].AsResponse();
|
||||
}
|
||||
|
||||
return _diskScanService.GetVideoFiles(path).Select(f => new {
|
||||
Path = f,
|
||||
RelativePath = path.GetRelativePath(f),
|
||||
Name = Path.GetFileName(f)
|
||||
}).AsResponse();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace NzbDrone.Api.Frontend.Mappers
|
||||
private readonly IAnalyticsService _analyticsService;
|
||||
private readonly Func<ICacheBreakerProvider> _cacheBreakProviderFactory;
|
||||
private readonly string _indexPath;
|
||||
private static readonly Regex ReplaceRegex = new Regex("(?<=(?:href|src)=\").*?(css|js)(?=\")", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex ReplaceRegex = new Regex("(?<=(?:href|src)=\").*?(css|js|png|ico|ics)(?=\")", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static String API_KEY;
|
||||
private static String URL_BASE;
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace NzbDrone.Api.History
|
||||
public Boolean QualityCutoffNotMet { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public string Indexer { get; set; }
|
||||
public string NzbInfoUrl { get; set; }
|
||||
public string ReleaseGroup { get; set; }
|
||||
public string DownloadId { get; set; }
|
||||
|
||||
|
||||
@@ -43,10 +43,12 @@ namespace NzbDrone.Api.Indexers
|
||||
_prioritizeDownloadDecision = prioritizeDownloadDecision;
|
||||
_downloadService = downloadService;
|
||||
_logger = logger;
|
||||
|
||||
GetResourceAll = GetReleases;
|
||||
Post["/"] = x => DownloadRelease(this.Bind<ReleaseResource>());
|
||||
|
||||
PostValidator.RuleFor(s => s.DownloadAllowed).Equal(true);
|
||||
PostValidator.RuleFor(s => s.Guid).NotEmpty();
|
||||
|
||||
_remoteEpisodeCache = cacheManager.GetCache<RemoteEpisode>(GetType(), "remoteEpisodes");
|
||||
}
|
||||
|
||||
40
src/NzbDrone.Api/ManualImport/ManualImportModule.cs
Normal file
40
src/NzbDrone.Api/ManualImport/ManualImportModule.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport.Manual;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Api.ManualImport
|
||||
{
|
||||
public class ManualImportModule : NzbDroneRestModule<ManualImportResource>
|
||||
{
|
||||
private readonly IManualImportService _manualImportService;
|
||||
|
||||
public ManualImportModule(IManualImportService manualImportService)
|
||||
: base("/manualimport")
|
||||
{
|
||||
_manualImportService = manualImportService;
|
||||
|
||||
GetResourceAll = GetMediaFiles;
|
||||
}
|
||||
|
||||
private List<ManualImportResource> GetMediaFiles()
|
||||
{
|
||||
var folderQuery = Request.Query.folder;
|
||||
var folder = (string)folderQuery.Value;
|
||||
|
||||
var downloadIdQuery = Request.Query.downloadId;
|
||||
var downloadId = (string)downloadIdQuery.Value;
|
||||
|
||||
return ToListResource(_manualImportService.GetMediaFiles(folder, downloadId)).Select(AddQualityWeight).ToList();
|
||||
}
|
||||
|
||||
private ManualImportResource AddQualityWeight(ManualImportResource item)
|
||||
{
|
||||
item.QualityWeight = Quality.DefaultQualityDefinitions.Single(q => q.Quality == item.Quality.Quality).Weight;
|
||||
item.QualityWeight += item.Quality.Revision.Real * 10;
|
||||
item.QualityWeight += item.Quality.Revision.Version;
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/NzbDrone.Api/ManualImport/ManualImportResource.cs
Normal file
32
src/NzbDrone.Api/ManualImport/ManualImportResource.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Api.Series;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Api.ManualImport
|
||||
{
|
||||
public class ManualImportResource : RestResource
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public string RelativePath { get; set; }
|
||||
public string Name { get; set; }
|
||||
public long Size { get; set; }
|
||||
public SeriesResource Series { get; set; }
|
||||
public int? SeasonNumber { get; set; }
|
||||
public List<EpisodeResource> Episodes { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public int QualityWeight { get; set; }
|
||||
public string DownloadId { get; set; }
|
||||
public IEnumerable<Rejection> Rejections { get; set; }
|
||||
|
||||
public int Id
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,11 @@ namespace NzbDrone.Api.Notifications
|
||||
{
|
||||
public class NotificationResource : ProviderResource
|
||||
{
|
||||
public String Link { get; set; }
|
||||
public Boolean OnGrab { get; set; }
|
||||
public Boolean OnDownload { get; set; }
|
||||
public Boolean OnUpgrade { get; set; }
|
||||
public String TestCommand { get; set; }
|
||||
public HashSet<Int32> Tags { get; set; }
|
||||
public string Link { get; set; }
|
||||
public bool OnGrab { get; set; }
|
||||
public bool OnDownload { get; set; }
|
||||
public bool OnUpgrade { get; set; }
|
||||
public string TestCommand { get; set; }
|
||||
public HashSet<int> Tags { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -100,6 +100,10 @@
|
||||
<Compile Include="Extensions\AccessControlHeaders.cs" />
|
||||
<Compile Include="Extensions\Pipelines\CorsPipeline.cs" />
|
||||
<Compile Include="Frontend\Mappers\LoginHtmlMapper.cs" />
|
||||
<Compile Include="Parse\ParseModule.cs" />
|
||||
<Compile Include="Parse\ParseResource.cs" />
|
||||
<Compile Include="ManualImport\ManualImportModule.cs" />
|
||||
<Compile Include="ManualImport\ManualImportResource.cs" />
|
||||
<Compile Include="Profiles\Delay\DelayProfileModule.cs" />
|
||||
<Compile Include="Profiles\Delay\DelayProfileResource.cs" />
|
||||
<Compile Include="Profiles\Delay\DelayProfileValidator.cs" />
|
||||
@@ -260,7 +264,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
@@ -268,4 +272,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
49
src/NzbDrone.Api/Parse/ParseModule.cs
Normal file
49
src/NzbDrone.Api/Parse/ParseModule.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Api.Parse
|
||||
{
|
||||
public class ParseModule : NzbDroneRestModule<ParseResource>
|
||||
{
|
||||
private readonly IParsingService _parsingService;
|
||||
|
||||
public ParseModule(IParsingService parsingService)
|
||||
{
|
||||
_parsingService = parsingService;
|
||||
|
||||
GetResourceSingle = Parse;
|
||||
}
|
||||
|
||||
private ParseResource Parse()
|
||||
{
|
||||
var title = Request.Query.Title.Value;
|
||||
var parsedEpisodeInfo = Parser.ParseTitle(title);
|
||||
|
||||
if (parsedEpisodeInfo == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo);
|
||||
|
||||
if (remoteEpisode == null)
|
||||
{
|
||||
remoteEpisode = new RemoteEpisode
|
||||
{
|
||||
ParsedEpisodeInfo = parsedEpisodeInfo
|
||||
};
|
||||
|
||||
return new ParseResource
|
||||
{
|
||||
Title = title,
|
||||
ParsedEpisodeInfo = parsedEpisodeInfo
|
||||
};
|
||||
}
|
||||
|
||||
var resource = ToResource(remoteEpisode);
|
||||
resource.Title = title;
|
||||
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/NzbDrone.Api/Parse/ParseResource.cs
Normal file
17
src/NzbDrone.Api/Parse/ParseResource.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Api.Series;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Api.Parse
|
||||
{
|
||||
public class ParseResource : RestResource
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; }
|
||||
public SeriesResource Series { get; set; }
|
||||
public List<EpisodeResource> Episodes { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -55,9 +55,9 @@ namespace NzbDrone.Api
|
||||
|
||||
private List<TProviderResource> GetAll()
|
||||
{
|
||||
var providerDefinitions = _providerFactory.All();
|
||||
var providerDefinitions = _providerFactory.All().OrderBy(p => p.ImplementationName);
|
||||
|
||||
var result = new List<TProviderResource>(providerDefinitions.Count);
|
||||
var result = new List<TProviderResource>(providerDefinitions.Count());
|
||||
|
||||
foreach (var definition in providerDefinitions)
|
||||
{
|
||||
@@ -69,14 +69,17 @@ namespace NzbDrone.Api
|
||||
result.Add(providerResource);
|
||||
}
|
||||
|
||||
return result;
|
||||
return result.OrderBy(p => p.Name).ToList();
|
||||
}
|
||||
|
||||
private int CreateProvider(TProviderResource providerResource)
|
||||
{
|
||||
var providerDefinition = GetDefinition(providerResource, false);
|
||||
|
||||
Test(providerDefinition, false);
|
||||
if (providerDefinition.Enable)
|
||||
{
|
||||
Test(providerDefinition, false);
|
||||
}
|
||||
|
||||
providerDefinition = _providerFactory.Create(providerDefinition);
|
||||
|
||||
@@ -87,7 +90,10 @@ namespace NzbDrone.Api
|
||||
{
|
||||
var providerDefinition = GetDefinition(providerResource, false);
|
||||
|
||||
Test(providerDefinition, false);
|
||||
if (providerDefinition.Enable)
|
||||
{
|
||||
Test(providerDefinition, false);
|
||||
}
|
||||
|
||||
_providerFactory.Update(providerDefinition);
|
||||
}
|
||||
@@ -118,7 +124,7 @@ namespace NzbDrone.Api
|
||||
|
||||
private Response GetTemplates()
|
||||
{
|
||||
var defaultDefinitions = _providerFactory.GetDefaultDefinitions().ToList();
|
||||
var defaultDefinitions = _providerFactory.GetDefaultDefinitions().OrderBy(p => p.ImplementationName).ToList();
|
||||
|
||||
var result = new List<TProviderResource>(defaultDefinitions.Count());
|
||||
|
||||
@@ -166,8 +172,6 @@ namespace NzbDrone.Api
|
||||
|
||||
protected virtual void Test(TProviderDefinition definition, bool includeWarnings)
|
||||
{
|
||||
if (!definition.Enable) return;
|
||||
|
||||
var validationResult = _providerFactory.Test(definition);
|
||||
|
||||
VerifyValidationResult(validationResult, includeWarnings);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Api.ClientSchema;
|
||||
using NzbDrone.Api.REST;
|
||||
|
||||
@@ -7,11 +6,12 @@ namespace NzbDrone.Api
|
||||
{
|
||||
public class ProviderResource : RestResource
|
||||
{
|
||||
public String Name { get; set; }
|
||||
public string Name { get; set; }
|
||||
public List<Field> Fields { get; set; }
|
||||
public String Implementation { get; set; }
|
||||
public String ConfigContract { get; set; }
|
||||
public String InfoLink { get; set; }
|
||||
public string ImplementationName { get; set; }
|
||||
public string Implementation { get; set; }
|
||||
public string ConfigContract { get; set; }
|
||||
public string InfoLink { get; set; }
|
||||
|
||||
public List<ProviderResource> Presets { get; set; }
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@ namespace NzbDrone.Api.RemotePathMappings
|
||||
{
|
||||
private readonly IRemotePathMappingService _remotePathMappingService;
|
||||
|
||||
public RemotePathMappingModule(IRemotePathMappingService remotePathMappingService, PathExistsValidator pathExistsValidator)
|
||||
public RemotePathMappingModule(IRemotePathMappingService remotePathMappingService,
|
||||
PathExistsValidator pathExistsValidator,
|
||||
MappedNetworkDriveValidator mappedNetworkDriveValidator)
|
||||
{
|
||||
_remotePathMappingService = remotePathMappingService;
|
||||
|
||||
@@ -31,6 +33,7 @@ namespace NzbDrone.Api.RemotePathMappings
|
||||
SharedValidator.RuleFor(c => c.LocalPath)
|
||||
.Cascade(CascadeMode.StopOnFirstFailure)
|
||||
.IsValidPath()
|
||||
.SetValidator(mappedNetworkDriveValidator)
|
||||
.SetValidator(pathExistsValidator);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ namespace NzbDrone.Api.RootFolders
|
||||
IBroadcastSignalRMessage signalRBroadcaster,
|
||||
RootFolderValidator rootFolderValidator,
|
||||
PathExistsValidator pathExistsValidator,
|
||||
DroneFactoryValidator droneFactoryValidator)
|
||||
DroneFactoryValidator droneFactoryValidator,
|
||||
MappedNetworkDriveValidator mappedNetworkDriveValidator)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_rootFolderService = rootFolderService;
|
||||
@@ -29,8 +30,9 @@ namespace NzbDrone.Api.RootFolders
|
||||
.Cascade(CascadeMode.StopOnFirstFailure)
|
||||
.IsValidPath()
|
||||
.SetValidator(rootFolderValidator)
|
||||
.SetValidator(pathExistsValidator)
|
||||
.SetValidator(droneFactoryValidator);
|
||||
.SetValidator(droneFactoryValidator)
|
||||
.SetValidator(mappedNetworkDriveValidator)
|
||||
.SetValidator(pathExistsValidator);
|
||||
}
|
||||
|
||||
private RootFolderResource GetRootFolder(int id)
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace NzbDrone.Api.Series
|
||||
private readonly ISearchForNewSeries _searchProxy;
|
||||
|
||||
public SeriesLookupModule(ISearchForNewSeries searchProxy)
|
||||
: base("/Series/lookup")
|
||||
: base("/series/lookup")
|
||||
{
|
||||
_searchProxy = searchProxy;
|
||||
Get["/"] = x => Search();
|
||||
|
||||
@@ -28,9 +28,9 @@ namespace NzbDrone.Api.Series
|
||||
}
|
||||
}
|
||||
|
||||
public Int32 EpisodeCount { get; set; }
|
||||
public Int32 EpisodeFileCount { get; set; }
|
||||
public Int64 SizeOnDisk { get; set; }
|
||||
public Int32? EpisodeCount { get; set; }
|
||||
public Int32? EpisodeFileCount { get; set; }
|
||||
public Int64? SizeOnDisk { get; set; }
|
||||
public SeriesStatusType Status { get; set; }
|
||||
public String ProfileName { get; set; }
|
||||
public String Overview { get; set; }
|
||||
|
||||
@@ -15,14 +15,14 @@ namespace NzbDrone.Api.System
|
||||
private readonly IRuntimeInfo _runtimeInfo;
|
||||
private readonly IRouteCacheProvider _routeCacheProvider;
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
private readonly IDatabase _database;
|
||||
private readonly IMainDatabase _database;
|
||||
private readonly ILifecycleService _lifecycleService;
|
||||
|
||||
public SystemModule(IAppFolderInfo appFolderInfo,
|
||||
IRuntimeInfo runtimeInfo,
|
||||
IRouteCacheProvider routeCacheProvider,
|
||||
IConfigFileProvider configFileProvider,
|
||||
IDatabase database,
|
||||
IMainDatabase database,
|
||||
ILifecycleService lifecycleService)
|
||||
: base("system")
|
||||
{
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net40" />
|
||||
<package id="NLog" version="2.1.0" targetFramework="net40" />
|
||||
<package id="ValueInjecter" version="2.3.3" targetFramework="net40" />
|
||||
</packages>
|
||||
</packages>
|
||||
|
||||
@@ -12,30 +12,43 @@ using NzbDrone.Host;
|
||||
using NzbDrone.Test.Common;
|
||||
using FluentAssertions;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Composition;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Download.TrackedDownloads;
|
||||
|
||||
namespace NzbDrone.App.Test
|
||||
{
|
||||
[TestFixture]
|
||||
public class ContainerFixture : TestBase
|
||||
{
|
||||
StartupContext args = new StartupContext("first", "second");
|
||||
private IContainer _container;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
var args = new StartupContext("first", "second");
|
||||
|
||||
_container = MainAppContainerBuilder.BuildContainer(args);
|
||||
|
||||
_container.Register<IMainDatabase>(new MainDatabase(null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_resolve_indexers()
|
||||
{
|
||||
MainAppContainerBuilder.BuildContainer(args).Resolve<IEnumerable<IIndexer>>().Should().NotBeEmpty();
|
||||
_container.Resolve<IEnumerable<IIndexer>>().Should().NotBeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_resolve_downloadclients()
|
||||
{
|
||||
MainAppContainerBuilder.BuildContainer(args).Resolve<IEnumerable<IDownloadClient>>().Should().NotBeEmpty();
|
||||
_container.Resolve<IEnumerable<IDownloadClient>>().Should().NotBeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void container_should_inject_itself()
|
||||
{
|
||||
var factory = MainAppContainerBuilder.BuildContainer(args).Resolve<IServiceFactory>();
|
||||
var factory = _container.Resolve<IServiceFactory>();
|
||||
|
||||
factory.Build<IIndexerFactory>().Should().NotBeNull();
|
||||
}
|
||||
@@ -44,22 +57,36 @@ namespace NzbDrone.App.Test
|
||||
public void should_resolve_command_executor_by_name()
|
||||
{
|
||||
var genericExecutor = typeof(IExecute<>).MakeGenericType(typeof(RssSyncCommand));
|
||||
var container = MainAppContainerBuilder.BuildContainer(args);
|
||||
|
||||
var executor = container.Resolve(genericExecutor);
|
||||
var executor = _container.Resolve(genericExecutor);
|
||||
|
||||
executor.Should().NotBeNull();
|
||||
executor.Should().BeAssignableTo<IExecute<RssSyncCommand>>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore("need to fix this at some point")]
|
||||
public void should_return_same_instance_of_singletons()
|
||||
{
|
||||
var container = MainAppContainerBuilder.BuildContainer(args);
|
||||
var first = _container.ResolveAll<IHandle<ApplicationShutdownRequested>>().OfType<Scheduler>().Single();
|
||||
var second = _container.ResolveAll<IHandle<ApplicationShutdownRequested>>().OfType<Scheduler>().Single();
|
||||
|
||||
var first = container.ResolveAll<IHandle<ApplicationShutdownRequested>>().OfType<Scheduler>().Single();
|
||||
var second = container.ResolveAll<IHandle<ApplicationShutdownRequested>>().OfType<Scheduler>().Single();
|
||||
first.Should().BeSameAs(second);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_same_instance_of_singletons_by_different_same_interface()
|
||||
{
|
||||
var first = _container.ResolveAll<IHandle<EpisodeGrabbedEvent>>().OfType<DownloadMonitoringService>().Single();
|
||||
var second = _container.ResolveAll<IHandle<EpisodeGrabbedEvent>>().OfType<DownloadMonitoringService>().Single();
|
||||
|
||||
first.Should().BeSameAs(second);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_same_instance_of_singletons_by_different_interfaces()
|
||||
{
|
||||
var first = _container.ResolveAll<IHandle<EpisodeGrabbedEvent>>().OfType<DownloadMonitoringService>().Single();
|
||||
var second = (DownloadMonitoringService)_container.Resolve<IExecute<CheckForFinishedDownloadCommand>>();
|
||||
|
||||
first.Should().BeSameAs(second);
|
||||
}
|
||||
|
||||
@@ -104,10 +104,16 @@
|
||||
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>xcopy /s /y "$(SolutionDir)\..\_output\NzbDrone.Mono.*" "$(TargetDir)"
|
||||
xcopy /s /y "$(SolutionDir)\..\_output\NzbDrone.Windows.*" "$(TargetDir)"</PostBuildEvent>
|
||||
<PostBuildEvent Condition="('$(OS)' == 'Windows_NT')">
|
||||
xcopy /s /y "$(SolutionDir)\..\_output\NzbDrone.Mono.*" "$(TargetDir)"
|
||||
xcopy /s /y "$(SolutionDir)\..\_output\NzbDrone.Windows.*" "$(TargetDir)"
|
||||
</PostBuildEvent>
|
||||
<PostBuildEvent Condition="('$(OS)' != 'Windows_NT')">
|
||||
cp -rv $(SolutionDir)\..\_output\NzbDrone.Mono.* $(TargetDir)
|
||||
cp -rv $(SolutionDir)\..\_output\NzbDrone.Windows.* $(TargetDir)
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
@@ -116,4 +122,4 @@ xcopy /s /y "$(SolutionDir)\..\_output\NzbDrone.Windows.*" "$(TargetDir)"</Pos
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -4,9 +4,12 @@ using System.IO;
|
||||
using System.Net;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Test.Common.Categories;
|
||||
using NLog;
|
||||
using NzbDrone.Common.TPL;
|
||||
|
||||
namespace NzbDrone.Common.Test.Http
|
||||
{
|
||||
@@ -14,6 +17,13 @@ namespace NzbDrone.Common.Test.Http
|
||||
[IntegrationTest]
|
||||
public class HttpClientFixture : TestBase<HttpClient>
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
Mocker.SetConstant<ICacheManager>(Mocker.Resolve<CacheManager>());
|
||||
Mocker.SetConstant<IRateLimitService>(Mocker.Resolve<RateLimitService>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_execute_simple_get()
|
||||
{
|
||||
@@ -100,7 +110,6 @@ namespace NzbDrone.Common.Test.Http
|
||||
response.Resource.Headers[header].ToString().Should().Be(value);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_not_download_file_with_error()
|
||||
{
|
||||
@@ -111,7 +120,102 @@ namespace NzbDrone.Common.Test.Http
|
||||
File.Exists(file).Should().BeFalse();
|
||||
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_send_cookie()
|
||||
{
|
||||
var request = new HttpRequest("http://eu.httpbin.org/get");
|
||||
request.AddCookie("my", "cookie");
|
||||
|
||||
var response = Subject.Get<HttpBinResource>(request);
|
||||
|
||||
response.Resource.Headers.Should().ContainKey("Cookie");
|
||||
|
||||
var cookie = response.Resource.Headers["Cookie"].ToString();
|
||||
|
||||
cookie.Should().Contain("my=cookie");
|
||||
}
|
||||
|
||||
public void GivenOldCookie()
|
||||
{
|
||||
var oldRequest = new HttpRequest("http://eu.httpbin.org/get");
|
||||
oldRequest.AddCookie("my", "cookie");
|
||||
|
||||
var oldClient = new HttpClient(Mocker.Resolve<ICacheManager>(), Mocker.Resolve<IRateLimitService>(), Mocker.Resolve<Logger>());
|
||||
|
||||
oldClient.Should().NotBeSameAs(Subject);
|
||||
|
||||
var oldResponse = oldClient.Get<HttpBinResource>(oldRequest);
|
||||
|
||||
oldResponse.Resource.Headers.Should().ContainKey("Cookie");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_preserve_cookie_during_session()
|
||||
{
|
||||
GivenOldCookie();
|
||||
|
||||
var request = new HttpRequest("http://eu.httpbin.org/get");
|
||||
|
||||
var response = Subject.Get<HttpBinResource>(request);
|
||||
|
||||
response.Resource.Headers.Should().ContainKey("Cookie");
|
||||
|
||||
var cookie = response.Resource.Headers["Cookie"].ToString();
|
||||
|
||||
cookie.Should().Contain("my=cookie");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_send_cookie_to_other_host()
|
||||
{
|
||||
GivenOldCookie();
|
||||
|
||||
var request = new HttpRequest("http://httpbin.org/get");
|
||||
|
||||
var response = Subject.Get<HttpBinResource>(request);
|
||||
|
||||
response.Resource.Headers.Should().NotContainKey("Cookie");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_store_response_cookie()
|
||||
{
|
||||
var requestSet = new HttpRequest("http://eu.httpbin.org/cookies/set?my=cookie");
|
||||
requestSet.AllowAutoRedirect = false;
|
||||
|
||||
var responseSet = Subject.Get(requestSet);
|
||||
|
||||
var request = new HttpRequest("http://eu.httpbin.org/get");
|
||||
|
||||
var response = Subject.Get<HttpBinResource>(request);
|
||||
|
||||
response.Resource.Headers.Should().NotContainKey("Cookie");
|
||||
|
||||
ExceptionVerification.IgnoreErrors();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_store_response_cookie()
|
||||
{
|
||||
var requestSet = new HttpRequest("http://eu.httpbin.org/cookies/set?my=cookie");
|
||||
requestSet.AllowAutoRedirect = false;
|
||||
requestSet.StoreResponseCookie = true;
|
||||
|
||||
var responseSet = Subject.Get(requestSet);
|
||||
|
||||
var request = new HttpRequest("http://eu.httpbin.org/get");
|
||||
|
||||
var response = Subject.Get<HttpBinResource>(request);
|
||||
|
||||
response.Resource.Headers.Should().ContainKey("Cookie");
|
||||
|
||||
var cookie = response.Resource.Headers["Cookie"].ToString();
|
||||
|
||||
cookie.Should().Contain("my=cookie");
|
||||
|
||||
ExceptionVerification.IgnoreErrors();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
<Compile Include="ServiceFactoryFixture.cs" />
|
||||
<Compile Include="ServiceProviderTests.cs" />
|
||||
<Compile Include="TPLTests\DebouncerFixture.cs" />
|
||||
<Compile Include="TPLTests\RateLimitServiceFixture.cs" />
|
||||
<Compile Include="WebClientTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -111,6 +112,14 @@
|
||||
<Project>{95C11A9E-56ED-456A-8447-2C89C1139266}</Project>
|
||||
<Name>NzbDrone.Host</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\NzbDrone.Mono\NzbDrone.Mono.csproj">
|
||||
<Project>{15ad7579-a314-4626-b556-663f51d97cd1}</Project>
|
||||
<Name>NzbDrone.Mono</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\NzbDrone.Windows\NzbDrone.Windows.csproj">
|
||||
<Project>{911284d3-f130-459e-836c-2430b6fbf21d}</Project>
|
||||
<Name>NzbDrone.Windows</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\NzbDrone\NzbDrone.csproj">
|
||||
<Project>{D12F7F2F-8A3C-415F-88FA-6DD061A84869}</Project>
|
||||
<Name>NzbDrone</Name>
|
||||
@@ -131,7 +140,7 @@
|
||||
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Host;
|
||||
@@ -16,11 +17,12 @@ namespace NzbDrone.Common.Test
|
||||
public void event_handlers_should_be_unique()
|
||||
{
|
||||
var container = MainAppContainerBuilder.BuildContainer(new StartupContext());
|
||||
container.Register<IMainDatabase>(new MainDatabase(null));
|
||||
container.Resolve<IAppFolderFactory>().Register();
|
||||
|
||||
Mocker.SetConstant(container);
|
||||
|
||||
var handlers = Subject.BuildAll<IHandle<ApplicationShutdownRequested>>()
|
||||
var handlers = Subject.BuildAll<IHandle<ApplicationStartedEvent>>()
|
||||
.Select(c => c.GetType().FullName);
|
||||
|
||||
handlers.Should().OnlyHaveUniqueItems();
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace NzbDrone.Common.Test.TPLTests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throttle_cals()
|
||||
public void should_throttle_calls()
|
||||
{
|
||||
var counter = new Counter();
|
||||
var debounceFunction = new Debouncer(counter.Hit, TimeSpan.FromMilliseconds(50));
|
||||
@@ -64,6 +64,62 @@ namespace NzbDrone.Common.Test.TPLTests
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_hold_the_call_while_paused()
|
||||
{
|
||||
var counter = new Counter();
|
||||
var debounceFunction = new Debouncer(counter.Hit, TimeSpan.FromMilliseconds(50));
|
||||
|
||||
debounceFunction.Pause();
|
||||
|
||||
debounceFunction.Execute();
|
||||
debounceFunction.Execute();
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
counter.Count.Should().Be(0);
|
||||
|
||||
debounceFunction.Execute();
|
||||
debounceFunction.Execute();
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
counter.Count.Should().Be(0);
|
||||
|
||||
debounceFunction.Resume();
|
||||
|
||||
Thread.Sleep(20);
|
||||
|
||||
counter.Count.Should().Be(0);
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
counter.Count.Should().Be(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_handle_pause_reentrancy()
|
||||
{
|
||||
var counter = new Counter();
|
||||
var debounceFunction = new Debouncer(counter.Hit, TimeSpan.FromMilliseconds(50));
|
||||
|
||||
debounceFunction.Pause();
|
||||
debounceFunction.Pause();
|
||||
|
||||
debounceFunction.Execute();
|
||||
debounceFunction.Execute();
|
||||
|
||||
debounceFunction.Resume();
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
counter.Count.Should().Be(0);
|
||||
|
||||
debounceFunction.Resume();
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
counter.Count.Should().Be(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
94
src/NzbDrone.Common.Test/TPLTests/RateLimitServiceFixture.cs
Normal file
94
src/NzbDrone.Common.Test/TPLTests/RateLimitServiceFixture.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.TPL;
|
||||
using NzbDrone.Test.Common;
|
||||
using FluentAssertions;
|
||||
|
||||
namespace NzbDrone.Common.Test.TPLTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class RateLimitServiceFixture : TestBase<RateLimitService>
|
||||
{
|
||||
private DateTime _epoch;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
// Make sure it's there so we don't affect measurements.
|
||||
Subject.GetType();
|
||||
|
||||
_epoch = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
private ConcurrentDictionary<string, DateTime> GetRateLimitStore()
|
||||
{
|
||||
var cache = Mocker.Resolve<ICacheManager>()
|
||||
.GetCache<ConcurrentDictionary<string, DateTime>>(typeof(RateLimitService), "rateLimitStore");
|
||||
|
||||
return cache.Get("rateLimitStore", () => new ConcurrentDictionary<string, DateTime>());
|
||||
}
|
||||
|
||||
private void GivenExisting(string key, DateTime dateTime)
|
||||
{
|
||||
GetRateLimitStore().AddOrUpdate(key, dateTime, (s, i) => dateTime);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_delay_if_unset()
|
||||
{
|
||||
var watch = Stopwatch.StartNew();
|
||||
Subject.WaitAndPulse("me", TimeSpan.FromMilliseconds(100));
|
||||
watch.Stop();
|
||||
|
||||
watch.ElapsedMilliseconds.Should().BeLessThan(100);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_delay_unrelated_key()
|
||||
{
|
||||
GivenExisting("other", _epoch + TimeSpan.FromMilliseconds(200));
|
||||
|
||||
var watch = Stopwatch.StartNew();
|
||||
Subject.WaitAndPulse("me", TimeSpan.FromMilliseconds(100));
|
||||
watch.Stop();
|
||||
|
||||
watch.ElapsedMilliseconds.Should().BeLessThan(50);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_wait_for_existing()
|
||||
{
|
||||
GivenExisting("me", _epoch + TimeSpan.FromMilliseconds(200));
|
||||
|
||||
var watch = Stopwatch.StartNew();
|
||||
Subject.WaitAndPulse("me", TimeSpan.FromMilliseconds(400));
|
||||
watch.Stop();
|
||||
|
||||
watch.ElapsedMilliseconds.Should().BeInRange(195, 250);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_extend_delay()
|
||||
{
|
||||
GivenExisting("me", _epoch + TimeSpan.FromMilliseconds(200));
|
||||
|
||||
Subject.WaitAndPulse("me", TimeSpan.FromMilliseconds(100));
|
||||
|
||||
(GetRateLimitStore()["me"] - _epoch).Should().BeGreaterOrEqualTo(TimeSpan.FromMilliseconds(300));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_add_delay()
|
||||
{
|
||||
Subject.WaitAndPulse("me", TimeSpan.FromMilliseconds(100));
|
||||
|
||||
(GetRateLimitStore()["me"] - _epoch).Should().BeGreaterOrEqualTo(TimeSpan.FromMilliseconds(100));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,6 +100,14 @@ namespace NzbDrone.Common.Cache
|
||||
_store.Clear();
|
||||
}
|
||||
|
||||
public void ClearExpired()
|
||||
{
|
||||
foreach (var cached in _store.Where(c => c.Value.IsExpired()))
|
||||
{
|
||||
Remove(cached.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<T> Values
|
||||
{
|
||||
get
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace NzbDrone.Common.Cache
|
||||
public interface ICached
|
||||
{
|
||||
void Clear();
|
||||
void ClearExpired();
|
||||
void Remove(string key);
|
||||
int Count { get; }
|
||||
}
|
||||
|
||||
@@ -51,7 +51,9 @@ namespace NzbDrone.Common.Composition
|
||||
|
||||
public void RegisterSingleton(Type service, Type implementation)
|
||||
{
|
||||
_container.Register(service, implementation).AsSingleton();
|
||||
var factory = CreateSingletonImplementationFactory(implementation);
|
||||
|
||||
_container.Register(service, factory);
|
||||
}
|
||||
|
||||
public IEnumerable<T> ResolveAll<T>() where T : class
|
||||
@@ -59,9 +61,23 @@ namespace NzbDrone.Common.Composition
|
||||
return _container.ResolveAll<T>();
|
||||
}
|
||||
|
||||
public void RegisterAllAsSingleton(Type registrationType, IEnumerable<Type> implementationList)
|
||||
public void RegisterAllAsSingleton(Type service, IEnumerable<Type> implementationList)
|
||||
{
|
||||
_container.RegisterMultiple(registrationType, implementationList).AsSingleton();
|
||||
foreach (var implementation in implementationList)
|
||||
{
|
||||
var factory = CreateSingletonImplementationFactory(implementation);
|
||||
|
||||
_container.Register(service, factory, implementation.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
private Func<TinyIoCContainer, NamedParameterOverloads, object> CreateSingletonImplementationFactory(Type implementation)
|
||||
{
|
||||
const string singleImplPrefix = "singleImpl_";
|
||||
|
||||
_container.Register(implementation, implementation, singleImplPrefix + implementation.FullName).AsSingleton();
|
||||
|
||||
return (c, p) => _container.Resolve(implementation, singleImplPrefix + implementation.FullName);
|
||||
}
|
||||
|
||||
public bool IsTypeRegistered(Type type)
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace NzbDrone.Common
|
||||
Console.WriteLine(" Commands:");
|
||||
Console.WriteLine(" /{0} Install the application as a Windows Service ({1}).", StartupContext.INSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME);
|
||||
Console.WriteLine(" /{0} Uninstall already installed Windows Service ({1}).", StartupContext.UNINSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME);
|
||||
Console.WriteLine(" /{0} Don't open NzbDrone in a browser", StartupContext.NO_BROWSER);
|
||||
Console.WriteLine(" /{0} Don't open Sonarr in a browser", StartupContext.NO_BROWSER);
|
||||
Console.WriteLine(" <No Arguments> Run application in console mode.");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
@@ -8,12 +6,15 @@ namespace NzbDrone.Common.Crypto
|
||||
{
|
||||
public static class HashConverter
|
||||
{
|
||||
private static SHA1 HashAlgorithm = SHA1.Create();
|
||||
private static readonly SHA1 Sha1 = SHA1.Create();
|
||||
|
||||
public static int GetHashInt31(string target)
|
||||
{
|
||||
var hash = HashAlgorithm.ComputeHash(Encoding.Default.GetBytes(target));
|
||||
|
||||
byte[] hash;
|
||||
lock (Sha1)
|
||||
{
|
||||
hash = Sha1.ComputeHash(Encoding.Default.GetBytes(target));
|
||||
}
|
||||
return BitConverter.ToInt32(hash, 0) & 0x7fffffff;
|
||||
}
|
||||
}
|
||||
|
||||
14
src/NzbDrone.Common/Disk/RelativeFileSystemModel.cs
Normal file
14
src/NzbDrone.Common/Disk/RelativeFileSystemModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace NzbDrone.Common.Disk
|
||||
{
|
||||
public class RelativeFileSystemModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Path { get; set; }
|
||||
public string RelativePath { get; set; }
|
||||
public string Extension { get; set; }
|
||||
public long Size { get; set; }
|
||||
public DateTime? LastModified { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -37,5 +37,10 @@ namespace NzbDrone.Common.Extensions
|
||||
{
|
||||
return !source.All(predicate);
|
||||
}
|
||||
|
||||
public static List<TResult> SelectList<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> predicate)
|
||||
{
|
||||
return source.Select(predicate).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,10 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.TPL;
|
||||
|
||||
namespace NzbDrone.Common.Http
|
||||
{
|
||||
@@ -22,15 +24,25 @@ namespace NzbDrone.Common.Http
|
||||
public class HttpClient : IHttpClient
|
||||
{
|
||||
private readonly Logger _logger;
|
||||
private readonly IRateLimitService _rateLimitService;
|
||||
private readonly ICached<CookieContainer> _cookieContainerCache;
|
||||
|
||||
public HttpClient(Logger logger)
|
||||
public HttpClient(ICacheManager cacheManager, IRateLimitService rateLimitService, Logger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_rateLimitService = rateLimitService;
|
||||
ServicePointManager.DefaultConnectionLimit = 12;
|
||||
|
||||
_cookieContainerCache = cacheManager.GetCache<CookieContainer>(typeof(HttpClient));
|
||||
}
|
||||
|
||||
public HttpResponse Execute(HttpRequest request)
|
||||
{
|
||||
if (request.RateLimit != TimeSpan.Zero)
|
||||
{
|
||||
_rateLimitService.WaitAndPulse(request.Url.Host, request.RateLimit);
|
||||
}
|
||||
|
||||
_logger.Trace(request);
|
||||
|
||||
var webRequest = (HttpWebRequest)WebRequest.Create(request.Url);
|
||||
@@ -59,15 +71,29 @@ namespace NzbDrone.Common.Http
|
||||
AddRequestHeaders(webRequest, request.Headers);
|
||||
}
|
||||
|
||||
var cookieContainer = _cookieContainerCache.Get("container", () => new CookieContainer());
|
||||
|
||||
if (request.Cookies.Count != 0)
|
||||
{
|
||||
webRequest.CookieContainer = new CookieContainer();
|
||||
foreach (var pair in request.Cookies)
|
||||
{
|
||||
webRequest.CookieContainer.Add(new Cookie(pair.Key, pair.Value, "/", request.Url.Host));
|
||||
cookieContainer.Add(new Cookie(pair.Key, pair.Value, "/", request.Url.Host)
|
||||
{
|
||||
Expires = DateTime.UtcNow.AddHours(1)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (request.StoreResponseCookie)
|
||||
{
|
||||
webRequest.CookieContainer = cookieContainer;
|
||||
}
|
||||
else
|
||||
{
|
||||
webRequest.CookieContainer = new CookieContainer();
|
||||
webRequest.CookieContainer.Add(cookieContainer.GetCookies(request.Url));
|
||||
}
|
||||
|
||||
if (!request.Body.IsNullOrWhiteSpace())
|
||||
{
|
||||
var bytes = request.Headers.GetEncodingFromContentType().GetBytes(request.Body.ToCharArray());
|
||||
|
||||
@@ -46,6 +46,8 @@ namespace NzbDrone.Common.Http
|
||||
public bool SuppressHttpError { get; set; }
|
||||
public bool AllowAutoRedirect { get; set; }
|
||||
public Dictionary<string, string> Cookies { get; private set; }
|
||||
public bool StoreResponseCookie { get; set; }
|
||||
public TimeSpan RateLimit { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace NzbDrone.Common.Instrumentation
|
||||
if (exception is NullReferenceException &&
|
||||
exception.ToString().Contains("Microsoft.AspNet.SignalR.Transports.TransportHeartbeat.ProcessServerCommand"))
|
||||
{
|
||||
Logger.Warn("SignalR Heartbeat error.");
|
||||
Logger.Warn("SignalR Heartbeat interupted");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
<Compile Include="ConvertBase32.cs" />
|
||||
<Compile Include="Crypto\HashProvider.cs" />
|
||||
<Compile Include="Disk\FileSystemLookupService.cs" />
|
||||
<Compile Include="Disk\RelativeFileSystemModel.cs" />
|
||||
<Compile Include="Disk\FileSystemModel.cs" />
|
||||
<Compile Include="Disk\FileSystemResult.cs" />
|
||||
<Compile Include="Extensions\DictionaryExtensions.cs" />
|
||||
@@ -177,7 +178,6 @@
|
||||
<Compile Include="Processes\ProcessProvider.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\SharedAssemblyInfo.cs" />
|
||||
<Compile Include="RateGate.cs" />
|
||||
<Compile Include="Reflection\ReflectionExtensions.cs" />
|
||||
<Compile Include="Extensions\ResourceExtensions.cs" />
|
||||
<Compile Include="Security\X509CertificateValidationPolicy.cs" />
|
||||
@@ -189,6 +189,7 @@
|
||||
<Compile Include="TinyIoC.cs" />
|
||||
<Compile Include="TPL\Debouncer.cs" />
|
||||
<Compile Include="TPL\LimitedConcurrencyLevelTaskScheduler.cs" />
|
||||
<Compile Include="TPL\RateLimitService.cs" />
|
||||
<Compile Include="TPL\TaskExtensions.cs" />
|
||||
<Compile Include="Extensions\TryParseExtensions.cs" />
|
||||
</ItemGroup>
|
||||
@@ -212,7 +213,7 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
/*
|
||||
* Code from: http://www.jackleitch.net/2010/10/better-rate-limiting-with-dot-net/
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
|
||||
namespace NzbDrone.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to control the rate of some occurrence per unit of time.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// To control the rate of an action using a <see cref="RateGate"/>,
|
||||
/// code should simply call <see cref="WaitToProceed()"/> prior to
|
||||
/// performing the action. <see cref="WaitToProceed()"/> will block
|
||||
/// the current thread until the action is allowed based on the rate
|
||||
/// limit.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This class is thread safe. A single <see cref="RateGate"/> instance
|
||||
/// may be used to control the rate of an occurrence across multiple
|
||||
/// threads.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class RateGate : IDisposable
|
||||
{
|
||||
// Semaphore used to count and limit the number of occurrences per
|
||||
// unit time.
|
||||
private readonly SemaphoreSlim _semaphore;
|
||||
|
||||
// Times (in millisecond ticks) at which the semaphore should be exited.
|
||||
private readonly ConcurrentQueue<int> _exitTimes;
|
||||
|
||||
// Timer used to trigger exiting the semaphore.
|
||||
private readonly Timer _exitTimer;
|
||||
|
||||
// Whether this instance is disposed.
|
||||
private bool _isDisposed;
|
||||
|
||||
/// <summary>
|
||||
/// Number of occurrences allowed per unit of time.
|
||||
/// </summary>
|
||||
public int Occurrences { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The length of the time unit, in milliseconds.
|
||||
/// </summary>
|
||||
public int TimeUnitMilliseconds { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="RateGate"/> with a rate of <paramref name="occurrences"/>
|
||||
/// per <paramref name="timeUnit"/>.
|
||||
/// </summary>
|
||||
/// <param name="occurrences">Number of occurrences allowed per unit of time.</param>
|
||||
/// <param name="timeUnit">Length of the time unit.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// If <paramref name="occurrences"/> or <paramref name="timeUnit"/> is negative.
|
||||
/// </exception>
|
||||
public RateGate(int occurrences, TimeSpan timeUnit)
|
||||
{
|
||||
// Check the arguments.
|
||||
if (occurrences <= 0)
|
||||
throw new ArgumentOutOfRangeException("occurrences", "Number of occurrences must be a positive integer");
|
||||
if (timeUnit != timeUnit.Duration())
|
||||
throw new ArgumentOutOfRangeException("timeUnit", "Time unit must be a positive span of time");
|
||||
if (timeUnit >= TimeSpan.FromMilliseconds(UInt32.MaxValue))
|
||||
throw new ArgumentOutOfRangeException("timeUnit", "Time unit must be less than 2^32 milliseconds");
|
||||
|
||||
Occurrences = occurrences;
|
||||
TimeUnitMilliseconds = (int)timeUnit.TotalMilliseconds;
|
||||
|
||||
// Create the semaphore, with the number of occurrences as the maximum count.
|
||||
_semaphore = new SemaphoreSlim(Occurrences, Occurrences);
|
||||
|
||||
// Create a queue to hold the semaphore exit times.
|
||||
_exitTimes = new ConcurrentQueue<int>();
|
||||
|
||||
// Create a timer to exit the semaphore. Use the time unit as the original
|
||||
// interval length because that's the earliest we will need to exit the semaphore.
|
||||
_exitTimer = new Timer(ExitTimerCallback, null, TimeUnitMilliseconds, -1);
|
||||
}
|
||||
|
||||
// Callback for the exit timer that exits the semaphore based on exit times
|
||||
// in the queue and then sets the timer for the nextexit time.
|
||||
private void ExitTimerCallback(object state)
|
||||
{
|
||||
// While there are exit times that are passed due still in the queue,
|
||||
// exit the semaphore and dequeue the exit time.
|
||||
int exitTime;
|
||||
while (_exitTimes.TryPeek(out exitTime)
|
||||
&& unchecked(exitTime - Environment.TickCount) <= 0)
|
||||
{
|
||||
_semaphore.Release();
|
||||
_exitTimes.TryDequeue(out exitTime);
|
||||
}
|
||||
|
||||
// Try to get the next exit time from the queue and compute
|
||||
// the time until the next check should take place. If the
|
||||
// queue is empty, then no exit times will occur until at least
|
||||
// one time unit has passed.
|
||||
int timeUntilNextCheck;
|
||||
if (_exitTimes.TryPeek(out exitTime))
|
||||
timeUntilNextCheck = unchecked(exitTime - Environment.TickCount);
|
||||
else
|
||||
timeUntilNextCheck = TimeUnitMilliseconds;
|
||||
|
||||
// Set the timer.
|
||||
_exitTimer.Change(timeUntilNextCheck, -1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Blocks the current thread until allowed to proceed or until the
|
||||
/// specified timeout elapses.
|
||||
/// </summary>
|
||||
/// <param name="millisecondsTimeout">Number of milliseconds to wait, or -1 to wait indefinitely.</param>
|
||||
/// <returns>true if the thread is allowed to proceed, or false if timed out</returns>
|
||||
public bool WaitToProceed(int millisecondsTimeout)
|
||||
{
|
||||
// Check the arguments.
|
||||
if (millisecondsTimeout < -1)
|
||||
throw new ArgumentOutOfRangeException("millisecondsTimeout");
|
||||
|
||||
CheckDisposed();
|
||||
|
||||
// Block until we can enter the semaphore or until the timeout expires.
|
||||
var entered = _semaphore.Wait(millisecondsTimeout);
|
||||
|
||||
// If we entered the semaphore, compute the corresponding exit time
|
||||
// and add it to the queue.
|
||||
if (entered)
|
||||
{
|
||||
var timeToExit = unchecked(Environment.TickCount + TimeUnitMilliseconds);
|
||||
_exitTimes.Enqueue(timeToExit);
|
||||
}
|
||||
|
||||
return entered;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Blocks the current thread until allowed to proceed or until the
|
||||
/// specified timeout elapses.
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns>true if the thread is allowed to proceed, or false if timed out</returns>
|
||||
public bool WaitToProceed(TimeSpan timeout)
|
||||
{
|
||||
return WaitToProceed((int)timeout.TotalMilliseconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Blocks the current thread indefinitely until allowed to proceed.
|
||||
/// </summary>
|
||||
public void WaitToProceed()
|
||||
{
|
||||
WaitToProceed(Timeout.Infinite);
|
||||
}
|
||||
|
||||
// Throws an ObjectDisposedException if this object is disposed.
|
||||
private void CheckDisposed()
|
||||
{
|
||||
if (_isDisposed)
|
||||
throw new ObjectDisposedException("RateGate is already disposed");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged resources held by an instance of this class.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged resources held by an instance of this class.
|
||||
/// </summary>
|
||||
/// <param name="isDisposing">Whether this object is being disposed.</param>
|
||||
protected virtual void Dispose(bool isDisposing)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
if (isDisposing)
|
||||
{
|
||||
// The semaphore and timer both implement IDisposable and
|
||||
// therefore must be disposed.
|
||||
_semaphore.Dispose();
|
||||
_exitTimer.Dispose();
|
||||
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace NzbDrone.Common.TPL
|
||||
{
|
||||
@@ -7,6 +8,9 @@ namespace NzbDrone.Common.TPL
|
||||
private readonly Action _action;
|
||||
private readonly System.Timers.Timer _timer;
|
||||
|
||||
private volatile int _paused;
|
||||
private volatile bool _triggered;
|
||||
|
||||
public Debouncer(Action action, TimeSpan debounceDuration)
|
||||
{
|
||||
_action = action;
|
||||
@@ -16,13 +20,45 @@ namespace NzbDrone.Common.TPL
|
||||
|
||||
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
_timer.Stop();
|
||||
_action();
|
||||
if (_paused == 0)
|
||||
{
|
||||
_triggered = false;
|
||||
_timer.Stop();
|
||||
_action();
|
||||
}
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
_timer.Start();
|
||||
lock (_timer)
|
||||
{
|
||||
_triggered = true;
|
||||
if (_paused == 0)
|
||||
{
|
||||
_timer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
lock (_timer)
|
||||
{
|
||||
_paused++;
|
||||
_timer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
lock (_timer)
|
||||
{
|
||||
_paused--;
|
||||
if (_paused == 0 && _triggered)
|
||||
{
|
||||
_timer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
src/NzbDrone.Common/TPL/RateLimitService.cs
Normal file
43
src/NzbDrone.Common/TPL/RateLimitService.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
|
||||
namespace NzbDrone.Common.TPL
|
||||
{
|
||||
public interface IRateLimitService
|
||||
{
|
||||
void WaitAndPulse(string key, TimeSpan interval);
|
||||
}
|
||||
|
||||
public class RateLimitService : IRateLimitService
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, DateTime> _rateLimitStore;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public RateLimitService(ICacheManager cacheManager, Logger logger)
|
||||
{
|
||||
_rateLimitStore = cacheManager.GetCache<ConcurrentDictionary<string, DateTime>>(GetType(), "rateLimitStore").Get("rateLimitStore", () => new ConcurrentDictionary<string, DateTime>());
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void WaitAndPulse(string key, TimeSpan interval)
|
||||
{
|
||||
var waitUntil = _rateLimitStore.AddOrUpdate(key,
|
||||
(s) => DateTime.UtcNow + interval,
|
||||
(s,i) => new DateTime(Math.Max(DateTime.UtcNow.Ticks, i.Ticks), DateTimeKind.Utc) + interval);
|
||||
|
||||
waitUntil -= interval;
|
||||
|
||||
var delay = waitUntil - DateTime.UtcNow;
|
||||
|
||||
if (delay.TotalSeconds > 0.0)
|
||||
{
|
||||
_logger.Trace("Rate Limit triggered, delaying '{0}' for {1:0.000} sec", key, delay.TotalSeconds);
|
||||
System.Threading.Thread.Sleep(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ namespace NzbDrone.Console
|
||||
{
|
||||
System.Console.WriteLine("");
|
||||
System.Console.WriteLine("");
|
||||
Logger.Fatal(exception.Message + ". This can happen if another instance of NzbDrone is already running or another application is using the port assinged to NzbDrone (default: 8989)");
|
||||
Logger.Fatal(exception.Message + ". This can happen if another instance of Sonarr is already running another application is using the same port (default: 8989) or the user has insufficient permissions");
|
||||
System.Console.WriteLine("Press any key to exit...");
|
||||
System.Console.ReadLine();
|
||||
Environment.Exit(1);
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
<PreBuildEvent>
|
||||
</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace NzbDrone.Core.Test.Blacklisting
|
||||
{
|
||||
Subject.Insert(_blacklist);
|
||||
|
||||
Subject.Blacklisted(_blacklist.SeriesId, _blacklist.SourceTitle.ToUpperInvariant()).Should().HaveCount(1);
|
||||
Subject.BlacklistedByTitle(_blacklist.SeriesId, _blacklist.SourceTitle.ToUpperInvariant()).Should().HaveCount(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,9 +28,12 @@ namespace NzbDrone.Core.Test.Blacklisting
|
||||
};
|
||||
|
||||
_event.Data.Add("publishedDate", DateTime.UtcNow.ToString("s") + "Z");
|
||||
_event.Data.Add("size", "1000");
|
||||
_event.Data.Add("indexer", "nzbs.org");
|
||||
_event.Data.Add("protocol", "1");
|
||||
_event.Data.Add("message", "Marked as failed");
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_add_to_repository()
|
||||
{
|
||||
@@ -39,5 +42,17 @@ namespace NzbDrone.Core.Test.Blacklisting
|
||||
Mocker.GetMock<IBlacklistRepository>()
|
||||
.Verify(v => v.Insert(It.Is<Blacklist>(b => b.EpisodeIds == _event.EpisodeIds)), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_add_to_repository_missing_size_and_protocol()
|
||||
{
|
||||
Subject.Handle(_event);
|
||||
|
||||
_event.Data.Remove("size");
|
||||
_event.Data.Remove("protocol");
|
||||
|
||||
Mocker.GetMock<IBlacklistRepository>()
|
||||
.Verify(v => v.Insert(It.Is<Blacklist>(b => b.EpisodeIds == _event.EpisodeIds)), Times.Once());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
using FluentAssertions;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace NzbDrone.Core.Test.DataAugmentationFixture.Scene
|
||||
{
|
||||
@@ -134,6 +135,48 @@ namespace NzbDrone.Core.Test.DataAugmentationFixture.Scene
|
||||
.Verify(v => v.All(), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_add_mapping_with_blank_title()
|
||||
{
|
||||
GivenProviders(new[] { _provider1 });
|
||||
|
||||
var fakeMappings = Builder<SceneMapping>.CreateListOfSize(2)
|
||||
.TheLast(1)
|
||||
.With(m => m.Title = null)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
_provider1.Setup(s => s.GetSceneMappings()).Returns(fakeMappings);
|
||||
|
||||
Mocker.GetMock<ISceneMappingRepository>().Setup(c => c.All()).Returns(_fakeMappings);
|
||||
|
||||
Subject.Execute(new UpdateSceneMappingCommand());
|
||||
|
||||
Mocker.GetMock<ISceneMappingRepository>().Verify(c => c.InsertMany(It.Is<IList<SceneMapping>>(m => !m.Any(s => s.Title.IsNullOrWhiteSpace()))), Times.Once());
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_add_mapping_with_blank_search_title()
|
||||
{
|
||||
GivenProviders(new[] { _provider1 });
|
||||
|
||||
var fakeMappings = Builder<SceneMapping>.CreateListOfSize(2)
|
||||
.TheLast(1)
|
||||
.With(m => m.SearchTerm = null)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
_provider1.Setup(s => s.GetSceneMappings()).Returns(fakeMappings);
|
||||
|
||||
Mocker.GetMock<ISceneMappingRepository>().Setup(c => c.All()).Returns(_fakeMappings);
|
||||
|
||||
Subject.Execute(new UpdateSceneMappingCommand());
|
||||
|
||||
Mocker.GetMock<ISceneMappingRepository>().Verify(c => c.InsertMany(It.Is<IList<SceneMapping>>(m => !m.Any(s => s. SearchTerm.IsNullOrWhiteSpace()))), Times.Once());
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
||||
private void AssertNoUpdate()
|
||||
{
|
||||
_provider1.Verify(c => c.GetSceneMappings(), Times.Once());
|
||||
|
||||
@@ -123,5 +123,19 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
WithFirstEpisodeUnmonitored();
|
||||
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultSingle, new SeasonSearchCriteria()).Accepted.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_episode_is_not_monitored_and_monitoredEpisodesOnly_flag_is_false()
|
||||
{
|
||||
WithFirstEpisodeUnmonitored();
|
||||
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultSingle, new SingleEpisodeSearchCriteria { MonitoredEpisodesOnly = false }).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_episode_is_not_monitored_and_monitoredEpisodesOnly_flag_is_true()
|
||||
{
|
||||
WithFirstEpisodeUnmonitored();
|
||||
_monitoredEpisodeSpecification.IsSatisfiedBy(_parseResultSingle, new SingleEpisodeSearchCriteria{ MonitoredEpisodesOnly = true}).Accepted.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class SameEpisodesSpecificationFixture : CoreTest<SameEpisodesSpecification>
|
||||
{
|
||||
private List<Episode> _episodes;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_episodes = Builder<Episode>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(e => e.EpisodeFileId = 1)
|
||||
.BuildList();
|
||||
}
|
||||
|
||||
private void GivenEpisodesInFile(List<Episode> episodes)
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.GetEpisodesByFileId(It.IsAny<int>()))
|
||||
.Returns(episodes);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_upgrade_when_new_release_contains_less_episodes()
|
||||
{
|
||||
GivenEpisodesInFile(_episodes);
|
||||
|
||||
Subject.IsSatisfiedBy(new List<Episode> { _episodes.First() }).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_upgrade_when_new_release_contains_more_episodes()
|
||||
{
|
||||
GivenEpisodesInFile(new List<Episode> { _episodes.First() });
|
||||
|
||||
Subject.IsSatisfiedBy(_episodes).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_upgrade_when_new_release_contains_the_same_episodes()
|
||||
{
|
||||
GivenEpisodesInFile(_episodes);
|
||||
|
||||
Subject.IsSatisfiedBy(_episodes).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_upgrade_when_release_contains_the_same_episodes_as_multiple_files()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(2)
|
||||
.BuildList();
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.GetEpisodesByFileId(episodes.First().EpisodeFileId))
|
||||
.Returns(new List<Episode> { episodes.First() });
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.GetEpisodesByFileId(episodes.Last().EpisodeFileId))
|
||||
.Returns(new List<Episode> { episodes.Last() });
|
||||
|
||||
Subject.IsSatisfiedBy(episodes).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,6 +151,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
|
||||
{
|
||||
GivenCompletedItem();
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(c => c.FolderExists(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
|
||||
Subject.RemoveItem("_Droned.S01E01.Pilot.1080p.WEB-DL-DRONE_0", true);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
@@ -158,9 +162,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveItem_should_throw_if_unknown_item()
|
||||
public void RemoveItem_should_ignore_if_unknown_item()
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() => Subject.RemoveItem("_Droned.S01E01.Pilot.1080p.WEB-DL-DRONE_0", true));
|
||||
Subject.RemoveItem("_Droned.S01E01.Pilot.1080p.WEB-DL-DRONE_0", true);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(c => c.DeleteFile(It.IsAny<string>()), Times.Never());
|
||||
|
||||
@@ -148,6 +148,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
|
||||
{
|
||||
GivenCompletedItem();
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(c => c.FolderExists(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
|
||||
Subject.RemoveItem("_Droned.S01E01.Pilot.1080p.WEB-DL-DRONE_0", true);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
@@ -155,9 +159,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveItem_should_throw_if_unknown_item()
|
||||
public void RemoveItem_should_ignore_if_unknown_item()
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() => Subject.RemoveItem("_Droned.S01E01.Pilot.1080p.WEB-DL-DRONE_0", true));
|
||||
Subject.RemoveItem("_Droned.S01E01.Pilot.1080p.WEB-DL-DRONE_0", true);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(c => c.DeleteFile(It.IsAny<string>()), Times.Never());
|
||||
|
||||
@@ -9,6 +9,7 @@ using NzbDrone.Core.Download.Clients.Nzbget;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Core.RemotePathMappings;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Download.Clients;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
||||
{
|
||||
@@ -139,6 +140,22 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
||||
Subject.GetItems().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveItem_should_delete_folder()
|
||||
{
|
||||
GivenQueue(null);
|
||||
GivenHistory(_completed);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.FolderExists(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
|
||||
Subject.RemoveItem("id", true);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.DeleteFolder(It.IsAny<string>(), true), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void queued_item_should_have_required_properties()
|
||||
{
|
||||
@@ -213,6 +230,19 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
||||
result.Status.Should().Be(DownloadItemStatus.Failed);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_report_deletestatus_dupe_as_warning()
|
||||
{
|
||||
_completed.DeleteStatus = "DUPE";
|
||||
|
||||
GivenQueue(null);
|
||||
GivenHistory(_completed);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
result.Status.Should().Be(DownloadItemStatus.Warning);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_report_unpackstatus_freespace_as_warning()
|
||||
{
|
||||
@@ -255,7 +285,6 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
||||
items.First().Status.Should().Be(DownloadItemStatus.Failed);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Download_should_return_unique_id()
|
||||
{
|
||||
@@ -268,6 +297,16 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
||||
id.Should().NotBeNullOrEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Download_should_throw_if_failed()
|
||||
{
|
||||
GivenFailedDownload();
|
||||
|
||||
var remoteEpisode = CreateRemoteEpisode();
|
||||
|
||||
Assert.Throws<DownloadClientException>(() => Subject.Download(remoteEpisode));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_should_ignore_downloads_from_other_categories()
|
||||
{
|
||||
@@ -319,5 +358,20 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
||||
|
||||
result.OutputPath.Should().Be(@"O:\mymount\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE".AsOsAgnostic());
|
||||
}
|
||||
|
||||
[TestCase("11.0", false)]
|
||||
[TestCase("12.0", true)]
|
||||
[TestCase("11.0-b30ef0134", false)]
|
||||
[TestCase("13.0-b30ef0134", true)]
|
||||
public void should_test_version(string version, bool expected)
|
||||
{
|
||||
Mocker.GetMock<INzbgetProxy>()
|
||||
.Setup(v => v.GetVersion(It.IsAny<NzbgetSettings>()))
|
||||
.Returns(version);
|
||||
|
||||
var error = Subject.Test();
|
||||
|
||||
error.IsValid.Should().Be(expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,6 +231,20 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
|
||||
VerifyFailed(result);
|
||||
}
|
||||
|
||||
[TestCase("[ TOWN ]-[ http://www.town.ag ]-[ ANIME ]-[Usenet Provider >> http://www.ssl- <<] - [Commie] Aldnoah Zero 18 [234C8FC7]", "[ TOWN ]-[ http-++www.town.ag ]-[ ANIME ]-[Usenet Provider http-++www.ssl- ] - [Commie] Aldnoah Zero 18 [234C8FC7].nzb")]
|
||||
public void Download_should_use_clean_title(string title, string filename)
|
||||
{
|
||||
GivenSuccessfulDownload();
|
||||
|
||||
var remoteEpisode = CreateRemoteEpisode();
|
||||
remoteEpisode.Release.Title = title;
|
||||
|
||||
var id = Subject.Download(remoteEpisode);
|
||||
|
||||
Mocker.GetMock<ISabnzbdProxy>()
|
||||
.Verify(v => v.DownloadNzb(It.IsAny<byte[]>(), filename, It.IsAny<string>(), It.IsAny<int>(), It.IsAny<SabnzbdSettings>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Download_should_return_unique_id()
|
||||
{
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
|
||||
|
||||
protected void GivenTvCategory()
|
||||
{
|
||||
_settings.TvCategory = "nzbdrone";
|
||||
_settings.TvCategory = "sonarr";
|
||||
}
|
||||
|
||||
protected void GivenFailedDownload()
|
||||
@@ -228,7 +228,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
|
||||
id.Should().NotBeNullOrEmpty();
|
||||
|
||||
Mocker.GetMock<ITransmissionProxy>()
|
||||
.Verify(v => v.AddTorrentFromData(It.IsAny<Byte[]>(), @"C:/Downloads/Finished/transmission/nzbdrone", It.IsAny<TransmissionSettings>()), Times.Once());
|
||||
.Verify(v => v.AddTorrentFromData(It.IsAny<Byte[]>(), @"C:/Downloads/Finished/transmission/sonarr", It.IsAny<TransmissionSettings>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -246,7 +246,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
|
||||
id.Should().NotBeNullOrEmpty();
|
||||
|
||||
Mocker.GetMock<ITransmissionProxy>()
|
||||
.Verify(v => v.AddTorrentFromData(It.IsAny<Byte[]>(), @"C:/Downloads/Finished/transmission/nzbdrone", It.IsAny<TransmissionSettings>()), Times.Once());
|
||||
.Verify(v => v.AddTorrentFromData(It.IsAny<Byte[]>(), @"C:/Downloads/Finished/transmission/sonarr", It.IsAny<TransmissionSettings>()), Times.Once());
|
||||
}
|
||||
|
||||
[TestCase("magnet:?xt=urn:btih:ZPBPA2P6ROZPKRHK44D5OW6NHXU5Z6KR&tr=udp", "CBC2F069FE8BB2F544EAE707D75BCD3DE9DCF951")]
|
||||
@@ -327,7 +327,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
|
||||
{
|
||||
GivenTvCategory();
|
||||
|
||||
_downloading.DownloadDir = @"C:/Downloads/Finished/transmission/nzbdrone";
|
||||
_downloading.DownloadDir = @"C:/Downloads/Finished/transmission/sonarr";
|
||||
|
||||
GivenTorrents(new List<TransmissionTorrent>
|
||||
{
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace NzbDrone.Core.Test.Download
|
||||
|
||||
var releaseInfo = Builder<ReleaseInfo>.CreateNew()
|
||||
.With(v => v.DownloadProtocol = Indexers.DownloadProtocol.Usenet)
|
||||
.With(v => v.DownloadUrl = "http://test.site/download1.ext")
|
||||
.Build();
|
||||
|
||||
_parseResult = Builder<RemoteEpisode>.CreateNew()
|
||||
|
||||
97
src/NzbDrone.Core.Test/Files/RSS/torznab_tpb.xml
Normal file
97
src/NzbDrone.Core.Test/Files/RSS/torznab_tpb.xml
Normal file
@@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="1.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:torznab="http://torznab.com/schemas/2015/feed">
|
||||
<channel>
|
||||
<atom:link href="http://localhost:9117/" rel="self" type="application/rss+xml" />
|
||||
<title>The Pirate Bay</title>
|
||||
<description>The worlds largest bittorrent indexer</description>
|
||||
<link>https://thepiratebay.se/</link>
|
||||
<lanuage>en-us</lanuage>
|
||||
<category>search</category>
|
||||
<image>
|
||||
<url>http://localhost:9117/logos/thepiratebay.png</url>
|
||||
<title>The Pirate Bay</title>
|
||||
<link>https://thepiratebay.se/</link>
|
||||
<description>The Pirate Bay</description>
|
||||
</image>
|
||||
<item>
|
||||
<title>Series Title S05E02 HDTV x264-Xclusive [eztv]</title>
|
||||
<guid>https://thepiratebay.se/torrent/11811366/Series_Title_S05E02_HDTV_x264-Xclusive_[eztv]</guid>
|
||||
<comments>https://thepiratebay.se/torrent/11811366/Series_Title_S05E02_HDTV_x264-Xclusive_[eztv]</comments>
|
||||
<pubDate>Sat, 11 Apr 2015 21:34:00 -0600</pubDate>
|
||||
<size>388895872</size>
|
||||
<description>Series Title S05E02 HDTV x264-Xclusive [eztv]</description>
|
||||
<link>magnet:?xt=urn:btih:9fb267cff5ae5603f07a347676ec3bf3e35f75e1&dn=Game+of+Thrones+S05E02+HDTV+x264-Xclusive+[eztv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969</link>
|
||||
<enclosure url="magnet:?xt=urn:btih:9fb267cff5ae5603f07a347676ec3bf3e35f75e1&dn=Game+of+Thrones+S05E02+HDTV+x264-Xclusive+[eztv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969" length="388895872" type="application/x-bittorrent;x-scheme-handler/magnet" />
|
||||
<torznab:attr name="magneturl" value="magnet:?xt=urn:btih:9fb267cff5ae5603f07a347676ec3bf3e35f75e1&dn=Game+of+Thrones+S05E02+HDTV+x264-Xclusive+[eztv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969" />
|
||||
<torznab:attr name="seeders" value="34128" />
|
||||
<torznab:attr name="peers" value="36724" />
|
||||
<torznab:attr name="infohash" value="9fb267cff5ae5603f07a347676ec3bf3e35f75e1" />
|
||||
<torznab:attr name="minimumratio" value="1" />
|
||||
<torznab:attr name="minimumseedtime" value="172800" />
|
||||
</item>
|
||||
<item>
|
||||
<title>Series Title S05E03 WEBRip XviD-FUM[ettv]</title>
|
||||
<guid>https://thepiratebay.se/torrent/11811373/Series_Title_S05E03_WEBRip_XviD-FUM[ettv]</guid>
|
||||
<comments>https://thepiratebay.se/torrent/11811373/Series_Title_S05E03_WEBRip_XviD-FUM[ettv]</comments>
|
||||
<pubDate>Sat, 11 Apr 2015 21:42:00 -0600</pubDate>
|
||||
<size>471722880</size>
|
||||
<description>Series Title S05E03 WEBRip XviD-FUM[ettv]</description>
|
||||
<link>magnet:?xt=urn:btih:c1f9f6bade11a4c46028b118053452460ab94be1&dn=Game+of+Thrones+S05E03+WEBRip+XviD-FUM[ettv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969</link>
|
||||
<enclosure url="magnet:?xt=urn:btih:c1f9f6bade11a4c46028b118053452460ab94be1&dn=Game+of+Thrones+S05E03+WEBRip+XviD-FUM[ettv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969" length="471722880" type="application/x-bittorrent;x-scheme-handler/magnet" />
|
||||
<torznab:attr name="magneturl" value="magnet:?xt=urn:btih:c1f9f6bade11a4c46028b118053452460ab94be1&dn=Game+of+Thrones+S05E03+WEBRip+XviD-FUM[ettv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969" />
|
||||
<torznab:attr name="seeders" value="28706" />
|
||||
<torznab:attr name="peers" value="30894" />
|
||||
<torznab:attr name="infohash" value="c1f9f6bade11a4c46028b118053452460ab94be1" />
|
||||
<torznab:attr name="minimumratio" value="1" />
|
||||
<torznab:attr name="minimumseedtime" value="172800" />
|
||||
</item>
|
||||
<item>
|
||||
<title>Series Title S05E01 HDTV x264-Xclusive</title>
|
||||
<guid>https://thepiratebay.se/torrent/11811268/Series_Title_S05E01_HDTV_x264-Xclusive</guid>
|
||||
<comments>https://thepiratebay.se/torrent/11811268/Series_Title_S05E01_HDTV_x264-Xclusive</comments>
|
||||
<pubDate>Sat, 11 Apr 2015 18:14:00 -0600</pubDate>
|
||||
<size>312339328</size>
|
||||
<description>Series Title S05E01 HDTV x264-Xclusive</description>
|
||||
<link>magnet:?xt=urn:btih:fd8b1062af0d8c2426cb4d180b86815ffa91b479&dn=Game+Of+Thrones+S05E01+HDTV+x264-Xclusive&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969</link>
|
||||
<enclosure url="magnet:?xt=urn:btih:fd8b1062af0d8c2426cb4d180b86815ffa91b479&dn=Game+Of+Thrones+S05E01+HDTV+x264-Xclusive&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969" length="312339328" type="application/x-bittorrent;x-scheme-handler/magnet" />
|
||||
<torznab:attr name="magneturl" value="magnet:?xt=urn:btih:fd8b1062af0d8c2426cb4d180b86815ffa91b479&dn=Game+Of+Thrones+S05E01+HDTV+x264-Xclusive&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969" />
|
||||
<torznab:attr name="seeders" value="26637" />
|
||||
<torznab:attr name="peers" value="27453" />
|
||||
<torznab:attr name="infohash" value="fd8b1062af0d8c2426cb4d180b86815ffa91b479" />
|
||||
<torznab:attr name="minimumratio" value="1" />
|
||||
<torznab:attr name="minimumseedtime" value="172800" />
|
||||
</item>
|
||||
<item>
|
||||
<title>Series Title S05E04 WEBRip XviD-FUM[ettv]</title>
|
||||
<guid>https://thepiratebay.se/torrent/11811448/Series_Title_S05E04_WEBRip_XviD-FUM[ettv]</guid>
|
||||
<comments>https://thepiratebay.se/torrent/11811448/Series_Title_S05E04_WEBRip_XviD-FUM[ettv]</comments>
|
||||
<pubDate>Sat, 11 Apr 2015 23:10:00 -0600</pubDate>
|
||||
<size>442970944</size>
|
||||
<description>Series Title S05E04 WEBRip XviD-FUM[ettv]</description>
|
||||
<link>magnet:?xt=urn:btih:30abe6b5816c758d327672a0fa58ff2b055ad3fe&dn=Game+of+Thrones+S05E04+WEBRip+XviD-FUM[ettv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969</link>
|
||||
<enclosure url="magnet:?xt=urn:btih:30abe6b5816c758d327672a0fa58ff2b055ad3fe&dn=Game+of+Thrones+S05E04+WEBRip+XviD-FUM[ettv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969" length="442970944" type="application/x-bittorrent;x-scheme-handler/magnet" />
|
||||
<torznab:attr name="magneturl" value="magnet:?xt=urn:btih:30abe6b5816c758d327672a0fa58ff2b055ad3fe&dn=Game+of+Thrones+S05E04+WEBRip+XviD-FUM[ettv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969" />
|
||||
<torznab:attr name="seeders" value="21551" />
|
||||
<torznab:attr name="peers" value="22711" />
|
||||
<torznab:attr name="infohash" value="30abe6b5816c758d327672a0fa58ff2b055ad3fe" />
|
||||
<torznab:attr name="minimumratio" value="1" />
|
||||
<torznab:attr name="minimumseedtime" value="172800" />
|
||||
</item>
|
||||
<item>
|
||||
<title>Series.Title.S03E19.HDTV.x264-LOL[ettv]</title>
|
||||
<guid>https://thepiratebay.se/torrent/11817918/Series.Title.S03E19.HDTV.x264-LOL[ettv]</guid>
|
||||
<comments>https://thepiratebay.se/torrent/11817918/Series.Title.S03E19.HDTV.x264-LOL[ettv]</comments>
|
||||
<pubDate>Wed, 15 Apr 2015 18:58:00 -0600</pubDate>
|
||||
<size>243951200</size>
|
||||
<description>Series.Title.S03E19.HDTV.x264-LOL[ettv]</description>
|
||||
<link>magnet:?xt=urn:btih:53896c2a6391a69a672041139e023c018c0f4aff&dn=Series.Title.S03E19.HDTV.x264-LOL[ettv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969</link>
|
||||
<enclosure url="magnet:?xt=urn:btih:53896c2a6391a69a672041139e023c018c0f4aff&dn=Series.Title.S03E19.HDTV.x264-LOL[ettv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969" length="243951200" type="application/x-bittorrent;x-scheme-handler/magnet" />
|
||||
<torznab:attr name="magneturl" value="magnet:?xt=urn:btih:53896c2a6391a69a672041139e023c018c0f4aff&dn=Series.Title.S03E19.HDTV.x264-LOL[ettv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969" />
|
||||
<torznab:attr name="seeders" value="15754" />
|
||||
<torznab:attr name="peers" value="17336" />
|
||||
<torznab:attr name="infohash" value="53896c2a6391a69a672041139e023c018c0f4aff" />
|
||||
<torznab:attr name="minimumratio" value="1" />
|
||||
<torznab:attr name="minimumseedtime" value="172800" />
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
@@ -1,7 +1,9 @@
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.Cloud;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Common.TPL;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.Framework
|
||||
@@ -16,7 +18,7 @@ namespace NzbDrone.Core.Test.Framework
|
||||
protected void UseRealHttp()
|
||||
{
|
||||
Mocker.SetConstant<IHttpProvider>(new HttpProvider(TestLogger));
|
||||
Mocker.SetConstant<IHttpClient>(new HttpClient(TestLogger));
|
||||
Mocker.SetConstant<IHttpClient>(new HttpClient(Mocker.Resolve<CacheManager>(), Mocker.Resolve<RateLimitService>(), TestLogger));
|
||||
Mocker.SetConstant<IDroneServicesRequestBuilder>(new DroneServicesHttpRequestBuilder());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,9 +88,31 @@ namespace NzbDrone.Core.Test.Framework
|
||||
protected virtual TestDatabase WithTestDb(Action<MigrationBase> beforeMigration)
|
||||
{
|
||||
var factory = Mocker.Resolve<DbFactory>();
|
||||
var database = factory.Create(MigrationType);
|
||||
var database = factory.Create(MigrationType, beforeMigration);
|
||||
Mocker.SetConstant(database);
|
||||
|
||||
switch (MigrationType)
|
||||
{
|
||||
case MigrationType.Main:
|
||||
{
|
||||
var mainDb = new MainDatabase(database);
|
||||
|
||||
Mocker.SetConstant<IMainDatabase>(mainDb);
|
||||
break;
|
||||
}
|
||||
case MigrationType.Log:
|
||||
{
|
||||
var logDb = new LogDatabase(database);
|
||||
|
||||
Mocker.SetConstant<ILogDatabase>(logDb);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new ArgumentException("Invalid MigrationType");
|
||||
}
|
||||
}
|
||||
|
||||
var testDb = new TestDatabase(database);
|
||||
|
||||
return testDb;
|
||||
|
||||
@@ -11,20 +11,13 @@ namespace NzbDrone.Core.Test.Framework
|
||||
{
|
||||
protected override TestDatabase WithTestDb(Action<MigrationBase> beforeMigration)
|
||||
{
|
||||
var factory = Mocker.Resolve<DbFactory>();
|
||||
|
||||
var database = factory.Create(MigrationType, m =>
|
||||
return base.WithTestDb(m =>
|
||||
{
|
||||
if (m.GetType() == typeof(TMigration))
|
||||
{
|
||||
beforeMigration(m);
|
||||
}
|
||||
});
|
||||
|
||||
var testDb = new TestDatabase(database);
|
||||
Mocker.SetConstant(database);
|
||||
|
||||
return testDb;
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
||||
|
||||
_xemSeries = Builder<Series>.CreateNew()
|
||||
.With(v => v.UseSceneNumbering = true)
|
||||
.With(v => v.Monitored = true)
|
||||
.Build();
|
||||
|
||||
_xemEpisodes = new List<Episode>();
|
||||
@@ -63,6 +64,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
||||
.With(v => v.EpisodeNumber, episodeNumber)
|
||||
.With(v => v.SceneSeasonNumber, sceneSeasonNumber)
|
||||
.With(v => v.SceneEpisodeNumber, sceneEpisodeNumber)
|
||||
.With(v => v.Monitored = true)
|
||||
.Build();
|
||||
|
||||
_xemEpisodes.Add(episode);
|
||||
@@ -136,7 +138,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
||||
|
||||
var allCriteria = WatchForSearchCriteria();
|
||||
|
||||
Subject.SeasonSearch(_xemSeries.Id, 1);
|
||||
Subject.SeasonSearch(_xemSeries.Id, 1, false);
|
||||
|
||||
var criteria = allCriteria.OfType<SeasonSearchCriteria>().ToList();
|
||||
|
||||
@@ -151,7 +153,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
||||
|
||||
var allCriteria = WatchForSearchCriteria();
|
||||
|
||||
Subject.SeasonSearch(_xemSeries.Id, 2);
|
||||
Subject.SeasonSearch(_xemSeries.Id, 2, false);
|
||||
|
||||
var criteria = allCriteria.OfType<SeasonSearchCriteria>().ToList();
|
||||
|
||||
@@ -167,7 +169,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
||||
|
||||
var allCriteria = WatchForSearchCriteria();
|
||||
|
||||
Subject.SeasonSearch(_xemSeries.Id, 4);
|
||||
Subject.SeasonSearch(_xemSeries.Id, 4, false);
|
||||
|
||||
var criteria1 = allCriteria.OfType<SeasonSearchCriteria>().ToList();
|
||||
var criteria2 = allCriteria.OfType<SingleEpisodeSearchCriteria>().ToList();
|
||||
@@ -187,7 +189,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
||||
|
||||
var allCriteria = WatchForSearchCriteria();
|
||||
|
||||
Subject.SeasonSearch(_xemSeries.Id, 7);
|
||||
Subject.SeasonSearch(_xemSeries.Id, 7, false);
|
||||
|
||||
var criteria = allCriteria.OfType<SeasonSearchCriteria>().ToList();
|
||||
|
||||
@@ -196,19 +198,55 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void season_search_for_anime_should_search_for_each_episode()
|
||||
public void season_search_for_anime_should_search_for_each_monitored_episode()
|
||||
{
|
||||
WithEpisodes();
|
||||
_xemSeries.SeriesType = SeriesTypes.Anime;
|
||||
var seasonNumber = 1;
|
||||
_xemEpisodes.ForEach(e => e.EpisodeFileId = 0);
|
||||
|
||||
var seasonNumber = 1;
|
||||
var allCriteria = WatchForSearchCriteria();
|
||||
|
||||
Subject.SeasonSearch(_xemSeries.Id, seasonNumber);
|
||||
Subject.SeasonSearch(_xemSeries.Id, seasonNumber, true);
|
||||
|
||||
var criteria = allCriteria.OfType<AnimeEpisodeSearchCriteria>().ToList();
|
||||
|
||||
criteria.Count.Should().Be(_xemEpisodes.Count(e => e.SeasonNumber == seasonNumber));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void season_search_for_anime_should_not_search_for_unmonitored_episodes()
|
||||
{
|
||||
WithEpisodes();
|
||||
_xemSeries.SeriesType = SeriesTypes.Anime;
|
||||
_xemEpisodes.ForEach(e => e.Monitored = false);
|
||||
_xemEpisodes.ForEach(e => e.EpisodeFileId = 0);
|
||||
|
||||
var seasonNumber = 1;
|
||||
var allCriteria = WatchForSearchCriteria();
|
||||
|
||||
Subject.SeasonSearch(_xemSeries.Id, seasonNumber, true);
|
||||
|
||||
var criteria = allCriteria.OfType<AnimeEpisodeSearchCriteria>().ToList();
|
||||
|
||||
criteria.Count.Should().Be(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void season_search_for_anime_should_not_search_for_episodes_with_files()
|
||||
{
|
||||
WithEpisodes();
|
||||
_xemSeries.SeriesType = SeriesTypes.Anime;
|
||||
_xemEpisodes.ForEach(e => e.EpisodeFileId = 1);
|
||||
|
||||
var seasonNumber = 1;
|
||||
var allCriteria = WatchForSearchCriteria();
|
||||
|
||||
Subject.SeasonSearch(_xemSeries.Id, seasonNumber, true);
|
||||
|
||||
var criteria = allCriteria.OfType<AnimeEpisodeSearchCriteria>().ToList();
|
||||
|
||||
criteria.Count.Should().Be(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
||||
.Returns(_series);
|
||||
|
||||
Mocker.GetMock<ISearchForNzb>()
|
||||
.Setup(s => s.SeasonSearch(_series.Id, It.IsAny<Int32>()))
|
||||
.Setup(s => s.SeasonSearch(_series.Id, It.IsAny<Int32>(), false))
|
||||
.Returns(new List<DownloadDecision>());
|
||||
|
||||
Mocker.GetMock<IProcessDownloadDecisions>()
|
||||
@@ -52,7 +52,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
||||
Subject.Execute(new SeriesSearchCommand{ SeriesId = _series.Id });
|
||||
|
||||
Mocker.GetMock<ISearchForNzb>()
|
||||
.Verify(v => v.SeasonSearch(_series.Id, It.IsAny<Int32>()), Times.Exactly(_series.Seasons.Count(s => s.Monitored)));
|
||||
.Verify(v => v.SeasonSearch(_series.Id, It.IsAny<Int32>(), false), Times.Exactly(_series.Seasons.Count(s => s.Monitored)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -68,9 +68,9 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
||||
};
|
||||
|
||||
Mocker.GetMock<ISearchForNzb>()
|
||||
.Setup(s => s.SeasonSearch(_series.Id, It.IsAny<Int32>()))
|
||||
.Setup(s => s.SeasonSearch(_series.Id, It.IsAny<Int32>(), false))
|
||||
.Returns(new List<DownloadDecision>())
|
||||
.Callback<Int32, Int32>((seriesId, seasonNumber) => seasonOrder.Add(seasonNumber));
|
||||
.Callback<int, int, bool>((seriesId, seasonNumber, missingOnly) => seasonOrder.Add(seasonNumber));
|
||||
|
||||
Subject.Execute(new SeriesSearchCommand { SeriesId = _series.Id });
|
||||
|
||||
|
||||
@@ -28,8 +28,7 @@ namespace NzbDrone.Core.Test.IndexerTests.BitMeTvTests
|
||||
public void should_parse_recent_feed_from_BitMeTv()
|
||||
{
|
||||
var recentFeed = ReadAllText(@"Files/RSS/BitMeTv.xml");
|
||||
|
||||
|
||||
|
||||
Mocker.GetMock<IHttpClient>()
|
||||
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
|
||||
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
|
||||
@@ -21,7 +21,7 @@ namespace NzbDrone.Core.Test.IndexerTests.BroadcastheNetTests
|
||||
Subject.Definition = new IndexerDefinition()
|
||||
{
|
||||
Name = "BroadcastheNet",
|
||||
Settings = new BroadcastheNetSettings() { ApiKey = "abc" }
|
||||
Settings = new BroadcastheNetSettings() { ApiKey = "abc", BaseUrl = "https://api.btnapps.net/" }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -127,5 +127,29 @@ namespace NzbDrone.Core.Test.IndexerTests.BroadcastheNetTests
|
||||
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_replace_https_http_as_needed()
|
||||
{
|
||||
var recentFeed = ReadAllText(@"Files/Indexers/BroadcastheNet/RecentFeed.json");
|
||||
|
||||
(Subject.Definition.Settings as BroadcastheNetSettings).BaseUrl = "http://api.btnapps.net/";
|
||||
|
||||
recentFeed = recentFeed.Replace("http:", "https:");
|
||||
|
||||
Mocker.GetMock<IHttpClient>()
|
||||
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST)))
|
||||
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
|
||||
|
||||
var releases = Subject.FetchRecent();
|
||||
|
||||
releases.Should().HaveCount(2);
|
||||
releases.First().Should().BeOfType<TorrentInfo>();
|
||||
|
||||
var torrentInfo = releases.First() as TorrentInfo;
|
||||
|
||||
torrentInfo.DownloadUrl.Should().Be("http://broadcasthe.net/torrents.php?action=download&id=123&authkey=123&torrent_pass=123");
|
||||
torrentInfo.InfoUrl.Should().Be("http://broadcasthe.net/torrents.php?id=237457&torrentid=123");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,14 @@ namespace NzbDrone.Core.Test.IndexerTests
|
||||
{
|
||||
public class TestIndexer : HttpIndexerBase<TestIndexerSettings>
|
||||
{
|
||||
public override string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Test Indexer";
|
||||
}
|
||||
}
|
||||
|
||||
public override DownloadProtocol Protocol { get { return DownloadProtocol.Usenet; } }
|
||||
|
||||
public Int32 _supportedPageSize;
|
||||
|
||||
@@ -57,5 +57,35 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests
|
||||
releaseInfo.Seeders.Should().Be(7);
|
||||
releaseInfo.Peers.Should().Be(7);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_parse_recent_feed_from_torznab_tpb()
|
||||
{
|
||||
var recentFeed = ReadAllText(@"Files/RSS/torznab_tpb.xml");
|
||||
|
||||
Mocker.GetMock<IHttpClient>()
|
||||
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
|
||||
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
|
||||
|
||||
var releases = Subject.FetchRecent();
|
||||
|
||||
releases.Should().HaveCount(5);
|
||||
|
||||
releases.First().Should().BeOfType<TorrentInfo>();
|
||||
var releaseInfo = releases.First() as TorrentInfo;
|
||||
|
||||
releaseInfo.Title.Should().Be("Series Title S05E02 HDTV x264-Xclusive [eztv]");
|
||||
releaseInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
|
||||
releaseInfo.MagnetUrl.Should().Be("magnet:?xt=urn:btih:9fb267cff5ae5603f07a347676ec3bf3e35f75e1&dn=Game+of+Thrones+S05E02+HDTV+x264-Xclusive+[eztv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969");
|
||||
releaseInfo.DownloadUrl.Should().Be("magnet:?xt=urn:btih:9fb267cff5ae5603f07a347676ec3bf3e35f75e1&dn=Game+of+Thrones+S05E02+HDTV+x264-Xclusive+[eztv]&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969");
|
||||
releaseInfo.InfoUrl.Should().Be("https://thepiratebay.se/torrent/11811366/Series_Title_S05E02_HDTV_x264-Xclusive_[eztv]");
|
||||
releaseInfo.CommentUrl.Should().Be("https://thepiratebay.se/torrent/11811366/Series_Title_S05E02_HDTV_x264-Xclusive_[eztv]");
|
||||
releaseInfo.Indexer.Should().Be(Subject.Definition.Name);
|
||||
releaseInfo.PublishDate.Should().Be(DateTime.Parse("Sat, 11 Apr 2015 21:34:00 -0600").ToUniversalTime());
|
||||
releaseInfo.Size.Should().Be(388895872);
|
||||
releaseInfo.InfoHash.Should().Be("9fb267cff5ae5603f07a347676ec3bf3e35f75e1");
|
||||
releaseInfo.Seeders.Should().Be(34128);
|
||||
releaseInfo.Peers.Should().Be(36724);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
@@ -7,10 +6,7 @@ using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.Commands;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
@@ -32,8 +28,6 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetParentFolder(It.IsAny<string>()))
|
||||
.Returns((string path) => Directory.GetParent(path).FullName);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void GivenParentFolderExists()
|
||||
@@ -61,8 +55,8 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
||||
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
|
||||
Mocker.GetMock<ICommandExecutor>()
|
||||
.Verify(v => v.PublishCommand(It.IsAny<CleanMediaFileDb>()), Times.Never());
|
||||
Mocker.GetMock<IMediaFileTableCleanupService>()
|
||||
.Verify(v => v.Clean(It.IsAny<Series>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -80,8 +74,8 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
||||
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
|
||||
Mocker.GetMock<ICommandExecutor>()
|
||||
.Verify(v => v.PublishCommand(It.IsAny<CleanMediaFileDb>()), Times.Never());
|
||||
Mocker.GetMock<IMediaFileTableCleanupService>()
|
||||
.Verify(v => v.Clean(It.IsAny<Series>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -182,5 +176,91 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _series), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_scan_Synology_eaDir()
|
||||
{
|
||||
GivenParentFolderExists();
|
||||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_series.Path, "@eaDir", "file1.mkv").AsOsAgnostic(),
|
||||
Path.Combine(_series.Path, "Season 1", "s01e01.mkv").AsOsAgnostic()
|
||||
});
|
||||
|
||||
Subject.Scan(_series);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _series), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_scan_thumb_folder()
|
||||
{
|
||||
GivenParentFolderExists();
|
||||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_series.Path, ".@__thumb", "file1.mkv").AsOsAgnostic(),
|
||||
Path.Combine(_series.Path, "Season 1", "s01e01.mkv").AsOsAgnostic()
|
||||
});
|
||||
|
||||
Subject.Scan(_series);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _series), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_scan_dotHack_folder()
|
||||
{
|
||||
GivenParentFolderExists();
|
||||
_series.Path = @"C:\Test\TV\.hack".AsOsAgnostic();
|
||||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_series.Path, "Season 1", "file1.mkv").AsOsAgnostic(),
|
||||
Path.Combine(_series.Path, "Season 1", "s01e01.mkv").AsOsAgnostic()
|
||||
});
|
||||
|
||||
Subject.Scan(_series);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 2), _series), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_find_files_at_root_of_series_folder()
|
||||
{
|
||||
GivenParentFolderExists();
|
||||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_series.Path, "file1.mkv").AsOsAgnostic(),
|
||||
Path.Combine(_series.Path, "s01e01.mkv").AsOsAgnostic()
|
||||
});
|
||||
|
||||
Subject.Scan(_series);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 2), _series), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_exclude_osx_metadata_files()
|
||||
{
|
||||
GivenParentFolderExists();
|
||||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_series.Path, "._24 The Status Quo Combustion.mp4").AsOsAgnostic(),
|
||||
Path.Combine(_series.Path, "24 The Status Quo Combustion.mkv").AsOsAgnostic()
|
||||
});
|
||||
|
||||
Subject.Scan(_series);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _series), Times.Once());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,6 +202,9 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists(It.IsAny<string>()))
|
||||
.Returns(false);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FileExists(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
|
||||
var fileName = @"C:\folder\file.mkv".AsOsAgnostic();
|
||||
|
||||
var result = Subject.ProcessPath(fileName);
|
||||
@@ -275,7 +278,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
imported.Add(new ImportDecision(localEpisode));
|
||||
|
||||
|
||||
var result = Subject.ProcessPath(fileName);
|
||||
Subject.ProcessPath(fileName);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(s => s.GetImportDecisions(It.IsAny<List<String>>(), It.IsAny<Series>(), It.Is<ParsedEpisodeInfo>(v => v.AbsoluteEpisodeNumbers.First() == 9), true), Times.Once());
|
||||
@@ -291,6 +294,9 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists(fileName))
|
||||
.Returns(false);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FileExists(fileName))
|
||||
.Returns(true);
|
||||
|
||||
var localEpisode = new LocalEpisode();
|
||||
|
||||
var imported = new List<ImportDecision>();
|
||||
@@ -302,6 +308,61 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
.Verify(s => s.GetImportDecisions(It.IsAny<List<String>>(), It.IsAny<Series>(), null, true), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_process_if_file_and_folder_do_not_exist()
|
||||
{
|
||||
var folderName = @"C:\media\ba09030e-1234-1234-1234-123456789abc\[HorribleSubs] Maria the Virgin Witch - 09 [720p]".AsOsAgnostic();
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists(folderName))
|
||||
.Returns(false);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FileExists(folderName))
|
||||
.Returns(false);
|
||||
|
||||
Subject.ProcessPath(folderName).Should().BeEmpty();
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(v => v.GetSeries(It.IsAny<string>()), Times.Never());
|
||||
|
||||
ExceptionVerification.ExpectedErrors(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_delete_if_no_files_were_imported()
|
||||
{
|
||||
GivenValidSeries();
|
||||
|
||||
var localEpisode = new LocalEpisode();
|
||||
|
||||
var imported = new List<ImportDecision>();
|
||||
imported.Add(new ImportDecision(localEpisode));
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<String>>(), It.IsAny<Series>(), null, true))
|
||||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<IImportApprovedEpisodes>()
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null))
|
||||
.Returns(new List<ImportResult>());
|
||||
|
||||
Mocker.GetMock<IDetectSample>()
|
||||
.Setup(s => s.IsSample(It.IsAny<Series>(),
|
||||
It.IsAny<QualityModel>(),
|
||||
It.IsAny<String>(),
|
||||
It.IsAny<Int64>(),
|
||||
It.IsAny<Int32>()))
|
||||
.Returns(true);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetFileSize(It.IsAny<string>()))
|
||||
.Returns(15.Megabytes());
|
||||
|
||||
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.DeleteFolder(It.IsAny<String>(), true), Times.Never());
|
||||
}
|
||||
|
||||
private void VerifyNoImport()
|
||||
{
|
||||
Mocker.GetMock<IImportApprovedEpisodes>().Verify(c => c.Import(It.IsAny<List<ImportDecision>>(), true, null),
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
||||
{
|
||||
Series = _series,
|
||||
Quality = _quality,
|
||||
Episodes = new List<Episode> { new Episode() },
|
||||
Path = @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV.avi"
|
||||
};
|
||||
|
||||
@@ -207,7 +208,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(c => c.GetLocalEpisode(It.IsAny<String>(), It.IsAny<Series>(), It.IsAny<ParsedEpisodeInfo>(), It.IsAny<Boolean>()))
|
||||
.Throws(new EpisodeNotFoundException("Episode not found"));
|
||||
.Returns(new LocalEpisode() { Path = "test" });
|
||||
|
||||
_videoFiles = new List<String>
|
||||
{
|
||||
@@ -218,10 +219,13 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
||||
|
||||
GivenVideoFiles(_videoFiles);
|
||||
|
||||
Subject.GetImportDecisions(_videoFiles, _series);
|
||||
var decisions = Subject.GetImportDecisions(_videoFiles, _series);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalEpisode(It.IsAny<String>(), It.IsAny<Series>(), It.IsAny<ParsedEpisodeInfo>(), It.IsAny<Boolean>()), Times.Exactly(_videoFiles.Count));
|
||||
|
||||
decisions.Should().HaveCount(3);
|
||||
decisions.First().Rejections.Should().NotBeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -6,7 +6,6 @@ using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.Commands;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
@@ -16,6 +15,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
{
|
||||
private const string DELETED_PATH = "ANY FILE WITH THIS PATH IS CONSIDERED DELETED!";
|
||||
private List<Episode> _episodes;
|
||||
private Series _series;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
@@ -24,9 +24,8 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Setup(s => s.GetSeries(It.IsAny<Int32>()))
|
||||
.Returns(Builder<Series>.CreateNew().Build());
|
||||
_series = Builder<Series>.CreateNew()
|
||||
.Build();
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(e => e.FileExists(It.Is<String>(c => !c.Contains(DELETED_PATH))))
|
||||
@@ -61,7 +60,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
|
||||
GivenEpisodeFiles(episodeFiles);
|
||||
|
||||
Subject.Execute(new CleanMediaFileDb(0));
|
||||
Subject.Clean(_series);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Verify(c => c.UpdateEpisode(It.IsAny<Episode>()), Times.Never());
|
||||
}
|
||||
@@ -76,7 +75,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
|
||||
GivenEpisodeFiles(episodeFiles);
|
||||
|
||||
Subject.Execute(new CleanMediaFileDb(0));
|
||||
Subject.Clean(_series);
|
||||
|
||||
Mocker.GetMock<IMediaFileService>().Verify(c => c.Delete(It.Is<EpisodeFile>(e => e.RelativePath == DELETED_PATH), DeleteMediaFileReason.MissingFromDisk), Times.Exactly(2));
|
||||
}
|
||||
@@ -92,7 +91,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
GivenEpisodeFiles(episodeFiles);
|
||||
GivenFilesAreNotAttachedToEpisode();
|
||||
|
||||
Subject.Execute(new CleanMediaFileDb(0));
|
||||
Subject.Clean(_series);
|
||||
|
||||
Mocker.GetMock<IMediaFileService>().Verify(c => c.Delete(It.IsAny<EpisodeFile>(), DeleteMediaFileReason.NoLinkedEpisodes), Times.Exactly(10));
|
||||
}
|
||||
@@ -102,7 +101,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
{
|
||||
GivenEpisodeFiles(new List<EpisodeFile>());
|
||||
|
||||
Subject.Execute(new CleanMediaFileDb(0));
|
||||
Subject.Clean(_series);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Verify(c => c.UpdateEpisode(It.Is<Episode>(e => e.EpisodeFileId == 0)), Times.Exactly(10));
|
||||
}
|
||||
@@ -117,7 +116,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
|
||||
GivenEpisodeFiles(episodeFiles);
|
||||
|
||||
Subject.Execute(new CleanMediaFileDb(0));
|
||||
Subject.Clean(_series);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Verify(c => c.UpdateEpisode(It.IsAny<Episode>()), Times.Never());
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.FileExists(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.OpenReadStream(It.IsAny<string>()))
|
||||
.Returns<string>(s => new FileStream(s, FileMode.Open, FileAccess.Read));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -54,5 +58,47 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
||||
info.Width.Should().Be(480);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void get_info_unicode()
|
||||
{
|
||||
var srcPath = Path.Combine(Directory.GetCurrentDirectory(), "Files", "Media", "H264_sample.mp4");
|
||||
|
||||
var tempPath = GetTempFilePath();
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
var path = Path.Combine(tempPath, "H264_Pok\u00E9mon.mkv");
|
||||
|
||||
File.Copy(srcPath, path);
|
||||
|
||||
var info = Subject.GetMediaInfo(path);
|
||||
|
||||
info.AudioBitrate.Should().Be(128000);
|
||||
info.AudioChannels.Should().Be(2);
|
||||
info.AudioFormat.Should().Be("AAC");
|
||||
info.AudioLanguages.Should().Be("English");
|
||||
info.AudioProfile.Should().Be("LC");
|
||||
info.Height.Should().Be(320);
|
||||
info.RunTime.Seconds.Should().Be(10);
|
||||
info.ScanType.Should().Be("Progressive");
|
||||
info.Subtitles.Should().Be("");
|
||||
info.VideoBitrate.Should().Be(193329);
|
||||
info.VideoCodec.Should().Be("AVC");
|
||||
info.VideoFps.Should().Be(24);
|
||||
info.Width.Should().Be(480);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_dispose_file_after_scanning_mediainfo()
|
||||
{
|
||||
var path = Path.Combine(Directory.GetCurrentDirectory(), "Files", "Media", "H264_sample.mp4");
|
||||
|
||||
var info = Subject.GetMediaInfo(path);
|
||||
|
||||
var stream = new FileStream(path, FileMode.Open, FileAccess.Write);
|
||||
|
||||
stream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,121 +1,121 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Commands.Tracking;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.Messaging.Commands
|
||||
{
|
||||
[TestFixture]
|
||||
public class CommandExecutorFixture : TestBase<CommandExecutor>
|
||||
{
|
||||
private Mock<IExecute<CommandA>> _executorA;
|
||||
private Mock<IExecute<CommandB>> _executorB;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_executorA = new Mock<IExecute<CommandA>>();
|
||||
_executorB = new Mock<IExecute<CommandB>>();
|
||||
|
||||
Mocker.GetMock<IServiceFactory>()
|
||||
.Setup(c => c.Build(typeof(IExecute<CommandA>)))
|
||||
.Returns(_executorA.Object);
|
||||
|
||||
Mocker.GetMock<IServiceFactory>()
|
||||
.Setup(c => c.Build(typeof(IExecute<CommandB>)))
|
||||
.Returns(_executorB.Object);
|
||||
|
||||
|
||||
Mocker.GetMock<ITrackCommands>()
|
||||
.Setup(c => c.FindExisting(It.IsAny<Command>()))
|
||||
.Returns<Command>(null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_publish_command_to_executor()
|
||||
{
|
||||
var commandA = new CommandA();
|
||||
|
||||
Subject.PublishCommand(commandA);
|
||||
|
||||
_executorA.Verify(c => c.Execute(commandA), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_publish_command_by_with_optional_arg_using_name()
|
||||
{
|
||||
Mocker.GetMock<IServiceFactory>().Setup(c => c.GetImplementations(typeof(Command)))
|
||||
.Returns(new List<Type> { typeof(CommandA), typeof(CommandB) });
|
||||
|
||||
Subject.PublishCommand(typeof(CommandA).FullName);
|
||||
_executorA.Verify(c => c.Execute(It.IsAny<CommandA>()), Times.Once());
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_not_publish_to_incompatible_executor()
|
||||
{
|
||||
var commandA = new CommandA();
|
||||
|
||||
Subject.PublishCommand(commandA);
|
||||
|
||||
_executorA.Verify(c => c.Execute(commandA), Times.Once());
|
||||
_executorB.Verify(c => c.Execute(It.IsAny<CommandB>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void broken_executor_should_throw_the_exception()
|
||||
{
|
||||
var commandA = new CommandA();
|
||||
|
||||
_executorA.Setup(c => c.Execute(It.IsAny<CommandA>()))
|
||||
.Throws(new NotImplementedException());
|
||||
|
||||
Assert.Throws<NotImplementedException>(() => Subject.PublishCommand(commandA));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void broken_executor_should_publish_executed_event()
|
||||
{
|
||||
var commandA = new CommandA();
|
||||
|
||||
_executorA.Setup(c => c.Execute(It.IsAny<CommandA>()))
|
||||
.Throws(new NotImplementedException());
|
||||
|
||||
Assert.Throws<NotImplementedException>(() => Subject.PublishCommand(commandA));
|
||||
|
||||
VerifyEventPublished<CommandExecutedEvent>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_publish_executed_event_on_success()
|
||||
{
|
||||
var commandA = new CommandA();
|
||||
Subject.PublishCommand(commandA);
|
||||
|
||||
VerifyEventPublished<CommandExecutedEvent>();
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandA : Command
|
||||
{
|
||||
public CommandA(int id = 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandB : Command
|
||||
{
|
||||
|
||||
public CommandB()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using Moq;
|
||||
//using NUnit.Framework;
|
||||
//using NzbDrone.Common;
|
||||
//using NzbDrone.Core.Messaging.Commands;
|
||||
//using NzbDrone.Core.Messaging.Commands.Tracking;
|
||||
//using NzbDrone.Core.Messaging.Events;
|
||||
//using NzbDrone.Test.Common;
|
||||
//
|
||||
//namespace NzbDrone.Core.Test.Messaging.Commands
|
||||
//{
|
||||
// [TestFixture]
|
||||
// public class CommandExecutorFixture : TestBase<CommandExecutor>
|
||||
// {
|
||||
// private Mock<IExecute<CommandA>> _executorA;
|
||||
// private Mock<IExecute<CommandB>> _executorB;
|
||||
//
|
||||
// [SetUp]
|
||||
// public void Setup()
|
||||
// {
|
||||
// _executorA = new Mock<IExecute<CommandA>>();
|
||||
// _executorB = new Mock<IExecute<CommandB>>();
|
||||
//
|
||||
// Mocker.GetMock<IServiceFactory>()
|
||||
// .Setup(c => c.Build(typeof(IExecute<CommandA>)))
|
||||
// .Returns(_executorA.Object);
|
||||
//
|
||||
// Mocker.GetMock<IServiceFactory>()
|
||||
// .Setup(c => c.Build(typeof(IExecute<CommandB>)))
|
||||
// .Returns(_executorB.Object);
|
||||
//
|
||||
//
|
||||
// Mocker.GetMock<ITrackCommands>()
|
||||
// .Setup(c => c.FindExisting(It.IsAny<Command>()))
|
||||
// .Returns<Command>(null);
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void should_publish_command_to_executor()
|
||||
// {
|
||||
// var commandA = new CommandA();
|
||||
//
|
||||
// Subject.Push(commandA);
|
||||
//
|
||||
// _executorA.Verify(c => c.Execute(commandA), Times.Once());
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void should_publish_command_by_with_optional_arg_using_name()
|
||||
// {
|
||||
// Mocker.GetMock<IServiceFactory>().Setup(c => c.GetImplementations(typeof(Command)))
|
||||
// .Returns(new List<Type> { typeof(CommandA), typeof(CommandB) });
|
||||
//
|
||||
// Subject.Push(typeof(CommandA).FullName);
|
||||
// _executorA.Verify(c => c.Execute(It.IsAny<CommandA>()), Times.Once());
|
||||
// }
|
||||
//
|
||||
//
|
||||
// [Test]
|
||||
// public void should_not_publish_to_incompatible_executor()
|
||||
// {
|
||||
// var commandA = new CommandA();
|
||||
//
|
||||
// Subject.Push(commandA);
|
||||
//
|
||||
// _executorA.Verify(c => c.Execute(commandA), Times.Once());
|
||||
// _executorB.Verify(c => c.Execute(It.IsAny<CommandB>()), Times.Never());
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void broken_executor_should_throw_the_exception()
|
||||
// {
|
||||
// var commandA = new CommandA();
|
||||
//
|
||||
// _executorA.Setup(c => c.Execute(It.IsAny<CommandA>()))
|
||||
// .Throws(new NotImplementedException());
|
||||
//
|
||||
// Assert.Throws<NotImplementedException>(() => Subject.Push(commandA));
|
||||
// }
|
||||
//
|
||||
//
|
||||
// [Test]
|
||||
// public void broken_executor_should_publish_executed_event()
|
||||
// {
|
||||
// var commandA = new CommandA();
|
||||
//
|
||||
// _executorA.Setup(c => c.Execute(It.IsAny<CommandA>()))
|
||||
// .Throws(new NotImplementedException());
|
||||
//
|
||||
// Assert.Throws<NotImplementedException>(() => Subject.Push(commandA));
|
||||
//
|
||||
// VerifyEventPublished<CommandExecutedEvent>();
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void should_publish_executed_event_on_success()
|
||||
// {
|
||||
// var commandA = new CommandA();
|
||||
// Subject.Push(commandA);
|
||||
//
|
||||
// VerifyEventPublished<CommandExecutedEvent>();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class CommandA : Command
|
||||
// {
|
||||
// public CommandA(int id = 0)
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class CommandB : Command
|
||||
// {
|
||||
//
|
||||
// public CommandB()
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -1,19 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Update.Commands;
|
||||
|
||||
namespace NzbDrone.Core.Test.Messaging.Commands
|
||||
{
|
||||
[TestFixture]
|
||||
public class CommandFixture
|
||||
{
|
||||
[Test]
|
||||
public void default_values()
|
||||
{
|
||||
var command = new ApplicationUpdateCommand();
|
||||
|
||||
command.Id.Should().NotBe(0);
|
||||
command.Name.Should().Be("ApplicationUpdate");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Messaging.Commands
|
||||
{
|
||||
[TestFixture]
|
||||
public class CommandQueueManagerFixture : CoreTest<CommandQueueManager>
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var id = 0;
|
||||
var commands = new List<CommandModel>();
|
||||
|
||||
Mocker.GetMock<ICommandRepository>()
|
||||
.Setup(s => s.Insert(It.IsAny<CommandModel>()))
|
||||
.Returns<CommandModel>(c =>
|
||||
{
|
||||
c.Id = id + 1;
|
||||
commands.Add(c);
|
||||
id++;
|
||||
|
||||
return c;
|
||||
});
|
||||
|
||||
Mocker.GetMock<ICommandRepository>()
|
||||
.Setup(s => s.Get(It.IsAny<int>()))
|
||||
.Returns<int>(c =>
|
||||
{
|
||||
return commands.SingleOrDefault(e => e.Id == c);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_remove_commands_for_five_minutes_after_they_end()
|
||||
{
|
||||
var command = Subject.Push<CheckForFinishedDownloadCommand>(new CheckForFinishedDownloadCommand());
|
||||
|
||||
Subject.Start(command);
|
||||
Subject.Complete(command, "All done");
|
||||
Subject.CleanCommands();
|
||||
|
||||
Subject.Get(command.Id).Should().NotBeNull();
|
||||
|
||||
Mocker.GetMock<ICommandRepository>()
|
||||
.Verify(v => v.Get(It.IsAny<int>()), Times.Never());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.MetadataSourceTests
|
||||
namespace NzbDrone.Core.Test.MetadataSource
|
||||
{
|
||||
[TestFixture]
|
||||
public class SearchSeriesComparerFixture : CoreTest
|
||||
@@ -1,21 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.MetadataSource.SkyHook;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Test.Common.Categories;
|
||||
|
||||
namespace NzbDrone.Core.Test.MetadataSourceTests
|
||||
namespace NzbDrone.Core.Test.MetadataSource.SkyHook
|
||||
{
|
||||
[TestFixture]
|
||||
[IntegrationTest]
|
||||
public class TvdbDataProxyFixture : CoreTest<TvDbProxy>
|
||||
public class SkyHookProxySearchFixture : CoreTest<SkyHookProxy>
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Notifications;
|
||||
using NzbDrone.Core.Notifications.Synology;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.NotificationTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class SynologyIndexerFixture : CoreTest<SynologyIndexer>
|
||||
{
|
||||
private Series _series;
|
||||
private DownloadMessage _upgrade;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_series = new Series()
|
||||
{
|
||||
Path = @"C:\Test\".AsOsAgnostic()
|
||||
};
|
||||
|
||||
_upgrade = new DownloadMessage()
|
||||
{
|
||||
Series = _series,
|
||||
|
||||
EpisodeFile = new EpisodeFile
|
||||
{
|
||||
RelativePath = "file1.S01E01E02.mkv"
|
||||
},
|
||||
|
||||
OldFiles = new List<EpisodeFile>
|
||||
{
|
||||
new EpisodeFile
|
||||
{
|
||||
RelativePath = "file1.S01E01.mkv"
|
||||
},
|
||||
new EpisodeFile
|
||||
{
|
||||
RelativePath = "file1.S01E02.mkv"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Subject.Definition = new NotificationDefinition
|
||||
{
|
||||
Settings = new SynologyIndexerSettings
|
||||
{
|
||||
UpdateLibrary = true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_library_if_disabled()
|
||||
{
|
||||
(Subject.Definition.Settings as SynologyIndexerSettings).UpdateLibrary = false;
|
||||
|
||||
Subject.AfterRename(_series);
|
||||
|
||||
Mocker.GetMock<ISynologyIndexerProxy>()
|
||||
.Verify(v => v.UpdateFolder(_series.Path), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_remove_old_episodes_on_upgrade()
|
||||
{
|
||||
Subject.OnDownload(_upgrade);
|
||||
|
||||
Mocker.GetMock<ISynologyIndexerProxy>()
|
||||
.Verify(v => v.DeleteFile(@"C:\Test\file1.S01E01.mkv".AsOsAgnostic()), Times.Once());
|
||||
|
||||
Mocker.GetMock<ISynologyIndexerProxy>()
|
||||
.Verify(v => v.DeleteFile(@"C:\Test\file1.S01E02.mkv".AsOsAgnostic()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_add_new_episode_on_upgrade()
|
||||
{
|
||||
Subject.OnDownload(_upgrade);
|
||||
|
||||
Mocker.GetMock<ISynologyIndexerProxy>()
|
||||
.Verify(v => v.AddFile(@"C:\Test\file1.S01E01E02.mkv".AsOsAgnostic()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_update_entire_series_folder_on_rename()
|
||||
{
|
||||
Subject.AfterRename(_series);
|
||||
|
||||
Mocker.GetMock<ISynologyIndexerProxy>()
|
||||
.Verify(v => v.UpdateFolder(@"C:\Test\".AsOsAgnostic()), Times.Once());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,6 +147,7 @@
|
||||
<Compile Include="DecisionEngineTests\RssSync\DelaySpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\RssSync\ProperSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\Search\SeriesSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\SameEpisodesSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\UpgradeDiskSpecificationFixture.cs" />
|
||||
<Compile Include="Download\CompletedDownloadServiceFixture.cs" />
|
||||
<Compile Include="Download\DownloadApprovedReportsTests\DownloadApprovedFixture.cs" />
|
||||
@@ -238,9 +239,11 @@
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\UpgradeSpecificationFixture.cs" />
|
||||
<Compile Include="MediaFiles\ImportApprovedEpisodesFixture.cs" />
|
||||
<Compile Include="MediaFiles\MediaFileRepositoryFixture.cs" />
|
||||
<Compile Include="MetadataSourceTests\TvdbDataProxyFixture.cs" />
|
||||
<Compile Include="MetadataSourceTests\SearchSeriesComparerFixture.cs" />
|
||||
<Compile Include="Messaging\Commands\CommandQueueManagerFixture.cs" />
|
||||
<Compile Include="MetadataSource\SkyHook\SkyHookProxySearchFixture.cs" />
|
||||
<Compile Include="MetadataSource\SearchSeriesComparerFixture.cs" />
|
||||
<Compile Include="MetadataSource\SkyHook\SkyHookProxyFixture.cs" />
|
||||
<Compile Include="NotificationTests\SynologyIndexerFixture.cs" />
|
||||
<Compile Include="OrganizerTests\FileNameBuilderTests\CleanTitleFixture.cs" />
|
||||
<Compile Include="OrganizerTests\FileNameBuilderTests\EpisodeTitleCollapseFixture.cs" />
|
||||
<Compile Include="OrganizerTests\FileNameBuilderTests\MultiEpisodeFixture.cs" />
|
||||
@@ -257,7 +260,6 @@
|
||||
<Compile Include="MediaFiles\UpgradeMediaFileServiceFixture.cs" />
|
||||
<Compile Include="Messaging\Commands\CommandEqualityComparerFixture.cs" />
|
||||
<Compile Include="Messaging\Commands\CommandExecutorFixture.cs" />
|
||||
<Compile Include="Messaging\Commands\CommandFixture.cs" />
|
||||
<Compile Include="Messaging\Events\EventAggregatorFixture.cs" />
|
||||
<Compile Include="Metadata\Consumers\Roksbox\FindMetadataFileFixture.cs" />
|
||||
<Compile Include="Metadata\Consumers\Wdtv\FindMetadataFileFixture.cs" />
|
||||
@@ -448,6 +450,9 @@
|
||||
<Content Include="Files\RSS\SizeParsing\omgwtfnzbs.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Files\RSS\torznab_tpb.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Files\RSS\wombles.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<SubType>Designer</SubType>
|
||||
@@ -501,7 +506,7 @@
|
||||
<PostBuildEvent>
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -77,6 +77,10 @@ namespace NzbDrone.Core.Test.ParserTests
|
||||
[TestCase("[Jumonji-Giri]_[F-B]_Kagihime_Monogatari_Eikyuu_Alice_Rondo_Ep08_(8246e542).mkv", "Kagihime Monogatari Eikyuu Alice Rondo", 8, 0, 0)]
|
||||
[TestCase("Knights of Sidonia - 01 [1080p 10b DTSHD-MA eng sub].mkv", "Knights of Sidonia", 1, 0, 0)]
|
||||
[TestCase("Series Title (2010) {01} Episode Title (1).hdtv-720p", "Series Title (2010)", 1, 0, 0)]
|
||||
[TestCase("[HorribleSubs] Shirobako - 20 [720p].mkv", "Shirobako", 20, 0, 0)]
|
||||
[TestCase("[Hatsuyuki] Dragon Ball Kai (2014) - 017 (115) [1280x720][B2CFBC0F]", "Dragon Ball Kai 2014", 17, 0, 0)]
|
||||
[TestCase("[Hatsuyuki] Dragon Ball Kai (2014) - 018 (116) [1280x720][C4A3B16E]", "Dragon Ball Kai 2014", 18, 0, 0)]
|
||||
[TestCase("Dragon Ball Kai (2014) - 39 (137) [v2][720p.HDTV][Unison Fansub]", "Dragon Ball Kai 2014", 39, 0, 0)]
|
||||
//[TestCase("", "", 0, 0, 0)]
|
||||
public void should_parse_absolute_numbers(string postTitle, string title, int absoluteEpisodeNumber, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
|
||||
@@ -186,28 +186,6 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
|
||||
.Verify(v => v.FindEpisode(It.IsAny<Int32>(), It.IsAny<Int32>(), It.IsAny<Int32>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_scene_numbering_when_season_0_for_anime()
|
||||
{
|
||||
GivenAbsoluteNumberingSeries();
|
||||
|
||||
Mocker.GetMock<ISceneMappingService>()
|
||||
.Setup(s => s.GetSeasonNumber(_parsedEpisodeInfo.SeriesTitle))
|
||||
.Returns(0);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.FindEpisodesBySceneNumbering(It.IsAny<Int32>(), 0, It.IsAny<Int32>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisodesBySceneNumbering(It.IsAny<Int32>(), 0, It.IsAny<Int32>()), Times.Once());
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisode(It.IsAny<Int32>(), 0, It.IsAny<Int32>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_look_for_episode_in_season_zero_if_absolute_special()
|
||||
{
|
||||
@@ -223,5 +201,77 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisode(It.IsAny<Int32>(), 0, It.IsAny<Int32>()), Times.Once());
|
||||
}
|
||||
|
||||
[TestCase(0)]
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
public void should_use_scene_numbering_when_scene_season_number_has_value(int seasonNumber)
|
||||
{
|
||||
GivenAbsoluteNumberingSeries();
|
||||
|
||||
Mocker.GetMock<ISceneMappingService>()
|
||||
.Setup(s => s.GetSeasonNumber(_parsedEpisodeInfo.SeriesTitle))
|
||||
.Returns(seasonNumber);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.FindEpisodesBySceneNumbering(It.IsAny<Int32>(), seasonNumber, It.IsAny<Int32>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisodesBySceneNumbering(It.IsAny<Int32>(), seasonNumber, It.IsAny<Int32>()), Times.Once());
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisode(It.IsAny<Int32>(), seasonNumber, It.IsAny<Int32>()), Times.Once());
|
||||
}
|
||||
|
||||
[TestCase(0)]
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
public void should_find_episode_by_season_and_scene_absolute_episode_number(int seasonNumber)
|
||||
{
|
||||
GivenAbsoluteNumberingSeries();
|
||||
|
||||
Mocker.GetMock<ISceneMappingService>()
|
||||
.Setup(s => s.GetSeasonNumber(_parsedEpisodeInfo.SeriesTitle))
|
||||
.Returns(seasonNumber);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.FindEpisodesBySceneNumbering(It.IsAny<Int32>(), seasonNumber, It.IsAny<Int32>()))
|
||||
.Returns(new List<Episode> { _episodes.First() });
|
||||
|
||||
Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisodesBySceneNumbering(It.IsAny<Int32>(), seasonNumber, It.IsAny<Int32>()), Times.Once());
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisode(It.IsAny<Int32>(), seasonNumber, It.IsAny<Int32>()), Times.Never());
|
||||
}
|
||||
|
||||
[TestCase(0)]
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
public void should_find_episode_by_season_and_absolute_episode_number_when_scene_absolute_episode_number_returns_multiple_results(int seasonNumber)
|
||||
{
|
||||
GivenAbsoluteNumberingSeries();
|
||||
|
||||
Mocker.GetMock<ISceneMappingService>()
|
||||
.Setup(s => s.GetSeasonNumber(_parsedEpisodeInfo.SeriesTitle))
|
||||
.Returns(seasonNumber);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.FindEpisodesBySceneNumbering(It.IsAny<Int32>(), seasonNumber, It.IsAny<Int32>()))
|
||||
.Returns(Builder<Episode>.CreateListOfSize(5).Build().ToList());
|
||||
|
||||
Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisodesBySceneNumbering(It.IsAny<Int32>(), seasonNumber, It.IsAny<Int32>()), Times.Once());
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisode(It.IsAny<Int32>(), seasonNumber, It.IsAny<Int32>()), Times.Once());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
||||
[TestCase(@"C:\Test\Series\Season 01\1 Pilot (1080p HD).mkv", 1, 1)]
|
||||
[TestCase(@"C:\Test\Series\Season 1\02 Honor Thy Father (1080p HD).m4v", 1, 2)]
|
||||
[TestCase(@"C:\Test\Series\Season 1\2 Honor Thy Father (1080p HD).m4v", 1, 2)]
|
||||
// [TestCase(@"C:\CSI.NY.S02E04.720p.WEB-DL.DD5.1.H.264\73696S02-04.mkv", 2, 4)] //Gets treated as S01E04 (because it gets parsed as anime)
|
||||
public void should_parse_from_path(string path, int season, int episode)
|
||||
{
|
||||
var result = Parser.Parser.ParsePath(path.AsOsAgnostic());
|
||||
|
||||
@@ -27,6 +27,11 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
|
||||
@"C:\Test\movie"
|
||||
};
|
||||
|
||||
GivenFiles();
|
||||
}
|
||||
|
||||
private void GivenFiles()
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetFiles(It.IsAny<String>(), SearchOption.AllDirectories))
|
||||
.Returns(_files);
|
||||
@@ -69,7 +74,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
|
||||
public void should_return_video_files_only()
|
||||
{
|
||||
var path = @"C:\Test\";
|
||||
var test = Subject.GetVideoFiles(path);
|
||||
|
||||
Subject.GetVideoFiles(path).Should().HaveCount(4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
|
||||
[Test]
|
||||
public void should_get_episodes()
|
||||
{
|
||||
var episodes = Subject.EpisodesBetweenDates(DateTime.Today.AddDays(-1), DateTime.Today.AddDays(3));
|
||||
var episodes = Subject.EpisodesBetweenDates(DateTime.Today.AddDays(-1), DateTime.Today.AddDays(3), false);
|
||||
episodes.Should().HaveCount(1);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user