1
0
mirror of https://github.com/Radarr/Radarr.git synced 2024-11-10 04:52:42 +01:00

Merge branch 'develop'

Conflicts:
	NzbDrone.Core.Test/MetadataSourceTests/TraktProxyFixture.cs
	NzbDrone.Core/Jobs/TaskManager.cs
	NzbDrone.Core/MetadataSource/TraktProxy.cs
	NzbDrone.Core/Tv/SeasonService.cs
	NzbDrone.Integration.Test/SeasonIntegrationTests.cs
This commit is contained in:
Keivan Beigi 2013-09-16 10:24:10 -07:00
commit 50b2aba5f9
485 changed files with 6559 additions and 3721 deletions

View File

@ -52,9 +52,10 @@ module.exports = function (grunt) {
options:{
dumpLineNumbers : 'false',
compress : false,
compress : true,
yuicompress : false,
ieCompat : false
ieCompat : true,
strictImports : true
},
bootstrap: {

View File

@ -28,8 +28,8 @@ public void schema_should_have_proper_fields()
var schema = SchemaBuilder.GenerateSchema(model);
schema.Should().Contain(c => c.Order == 1 && c.Name == "LastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" && c.Value == "Poop");
schema.Should().Contain(c => c.Order == 0 && c.Name == "FirstName" && c.Label == "First Name" && c.HelpText == "Your First Name" && c.Value == "Bob");
schema.Should().Contain(c => c.Order == 1 && c.Name == "LastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" && (string) c.Value == "Poop");
schema.Should().Contain(c => c.Order == 0 && c.Name == "FirstName" && c.Label == "First Name" && c.HelpText == "Your First Name" && (string) c.Value == "Bob");
}
}

View File

@ -37,9 +37,6 @@ public void Setup()
"Windows"
};
Mocker.GetMock<IDiskProvider>()
.SetupGet(s => s.SpecialFolders)
.Returns(new HashSet<string> { "$recycle.bin", "system volume information", "recycler" });
}
private void SetupFolders(string root)

View File

@ -4,6 +4,7 @@
using FluentAssertions;
using Marr.Data;
using NUnit.Framework;
using NzbDrone.Api.Commands;
using NzbDrone.Api.Config;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.History;
@ -13,16 +14,16 @@
using NzbDrone.Api.Qualities;
using NzbDrone.Api.RootFolders;
using NzbDrone.Api.Series;
using NzbDrone.Api.Update;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Instrumentation;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Update;
using NzbDrone.Core.Update.Commands;
using NzbDrone.Test.Common;
using System.Linq;
@ -36,13 +37,13 @@ public class ResourceMappingFixture : TestBase
[TestCase(typeof(RootFolder), typeof(RootFolderResource))]
[TestCase(typeof(NamingConfig), typeof(NamingConfigResource))]
[TestCase(typeof(Indexer), typeof(IndexerResource))]
[TestCase(typeof(ReportInfo), typeof(ReleaseResource))]
[TestCase(typeof(ReleaseInfo), typeof(ReleaseResource))]
[TestCase(typeof(ParsedEpisodeInfo), typeof(ReleaseResource))]
[TestCase(typeof(DownloadDecision), typeof(ReleaseResource))]
[TestCase(typeof(Core.History.History), typeof(HistoryResource))]
[TestCase(typeof(UpdatePackage), typeof(UpdateResource))]
[TestCase(typeof(Quality), typeof(QualityResource))]
[TestCase(typeof(Log), typeof(LogResource))]
[TestCase(typeof(Command), typeof(CommandResource))]
public void matching_fields(Type modelType, Type resourceType)
{
MappingValidation.ValidateMapping(modelType, resourceType);
@ -116,6 +117,15 @@ public void should_map_qualityprofile()
profileResource.InjectTo<QualityProfile>();
}
[Test]
public void should_map_tracked_command()
{
var profileResource = new ApplicationUpdateCommand();
profileResource.InjectTo<CommandResource>();
}
}
public class ModelWithLazy

View File

@ -1,37 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Api.Mapping;
using NzbDrone.Api.Validation;
using NzbDrone.Common.Composition;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.Messaging;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Commands.Tracking;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.ProgressMessaging;
namespace NzbDrone.Api.Commands
{
public class CommandModule : NzbDroneRestModule<CommandResource>
public class CommandModule : NzbDroneRestModuleWithSignalR<CommandResource, Command>, IHandle<CommandUpdatedEvent>
{
private readonly IMessageAggregator _messageAggregator;
private readonly ICommandExecutor _commandExecutor;
private readonly IContainer _container;
private readonly ITrackCommands _trackCommands;
public CommandModule(IMessageAggregator messageAggregator, IContainer container)
public CommandModule(ICommandExecutor commandExecutor, IContainer container, ITrackCommands trackCommands)
: base(commandExecutor)
{
_messageAggregator = messageAggregator;
_commandExecutor = commandExecutor;
_container = container;
_trackCommands = trackCommands;
Post["/"] = x => RunCommand(ReadResourceFromRequest());
GetResourceById = GetCommand;
CreateResource = StartCommand;
GetResourceAll = GetAllCommands;
PostValidator.RuleFor(c => c.Name).NotBlank();
}
private Response RunCommand(CommandResource resource)
private CommandResource GetCommand(int id)
{
return _trackCommands.GetById(id).InjectTo<CommandResource>();
}
private int StartCommand(CommandResource commandResource)
{
var commandType =
_container.GetImplementations(typeof(ICommand))
_container.GetImplementations(typeof(Command))
.Single(c => c.Name.Replace("Command", "")
.Equals(resource.Command, StringComparison.InvariantCultureIgnoreCase));
.Equals(commandResource.Name, StringComparison.InvariantCultureIgnoreCase));
dynamic command = Request.Body.FromJson(commandType);
_messageAggregator.PublishCommand(command);
return resource.AsResponse(HttpStatusCode.Created);
var trackedCommand = (Command)_commandExecutor.PublishCommandAsync(command);
return trackedCommand.Id;
}
private List<CommandResource> GetAllCommands()
{
return ToListResource(_trackCommands.RunningCommands);
}
public void Handle(CommandUpdatedEvent message)
{
if (message.Command.SendUpdatesToClient)
{
BroadcastResourceChange(ModelAction.Updated, message.Command.Id);
}
}
}
}

View File

@ -1,9 +1,16 @@
using NzbDrone.Api.REST;
using System;
using NzbDrone.Api.REST;
using NzbDrone.Core.Messaging.Commands.Tracking;
namespace NzbDrone.Api.Commands
{
public class CommandResource : RestResource
{
public string Command { get; set; }
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; }
}
}

View File

@ -1,24 +0,0 @@
using System;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Infrastructure;
using NzbDrone.Api.SignalR;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.Download;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Episodes
{
public class EpisodeConnection : BasicResourceConnection<Episode>, IHandleAsync<EpisodeGrabbedEvent>
{
public override string Resource
{
get { return "/Episodes"; }
}
public void HandleAsync(EpisodeGrabbedEvent message)
{
var context = ((ConnectionManager)GlobalHost.ConnectionManager).GetConnection(GetType());
context.Connection.Broadcast(message);
}
}
}

View File

@ -9,7 +9,6 @@ public abstract class ApiException : Exception
{
public object Content { get; private set; }
public HttpStatusCode StatusCode { get; private set; }
protected ApiException(HttpStatusCode statusCode, object content = null)

View File

@ -3,6 +3,7 @@
using NLog;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core;
using HttpStatusCode = Nancy.HttpStatusCode;
namespace NzbDrone.Api.ErrorManagement
@ -35,9 +36,20 @@ public Response HandleException(NancyContext context, Exception exception)
return validationException.Errors.AsResponse(HttpStatusCode.BadRequest);
}
var clientException = exception as NzbDroneClientException;
if (clientException != null)
{
return new ErrorModel
{
Message = exception.Message,
Description = exception.ToString()
}.AsResponse((HttpStatusCode)clientException.StatusCode);
}
_logger.FatalException("Request Failed", exception);
return new ErrorModel()
return new ErrorModel
{
Message = exception.Message,
Description = exception.ToString()

View File

@ -1,5 +1,4 @@
using System;
using Nancy;
using Nancy;
using Nancy.Bootstrapper;
using NzbDrone.Api.Frontend;

View File

@ -12,7 +12,6 @@ public static class ReqResExtensions
{
private static readonly NancyJsonSerializer NancySerializer = new NancyJsonSerializer();
public static readonly string LastModified = BuildInfo.BuildDateTime.ToString("r");
public static T FromJson<T>(this Stream body) where T : class, new()
@ -25,7 +24,6 @@ public static T FromJson<T>(this Stream body, Type type)
return (T)FromJson(body, type);
}
public static object FromJson(this Stream body, Type type)
{
var reader = new StreamReader(body, true);

View File

@ -6,7 +6,6 @@
using NzbDrone.Core.Indexers;
using Omu.ValueInjecter;
using FluentValidation;
using NzbDrone.Api.Extensions;
using NzbDrone.Api.Mapping;
namespace NzbDrone.Api.Indexers

View File

@ -1,7 +1,9 @@
using System.Collections.Generic;
using Nancy;
using NLog;
using NzbDrone.Api.Mapping;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Download;
using NzbDrone.Core.IndexerSearch;
using NzbDrone.Core.Indexers;
@ -40,7 +42,7 @@ public ReleaseModule(IFetchAndParseRss rssFetcherAndParser,
private Response DownloadRelease(ReleaseResource release)
{
var remoteEpisode = _parsingService.Map(release.InjectTo<ParsedEpisodeInfo>(), 0);
remoteEpisode.Report = release.InjectTo<ReportInfo>();
remoteEpisode.Release = release.InjectTo<ReleaseInfo>();
_downloadService.DownloadReport(remoteEpisode);
@ -60,6 +62,7 @@ private List<ReleaseResource> GetReleases()
private List<ReleaseResource> GetEpisodeReleases(int episodeId)
{
var decisions = _nzbSearchService.EpisodeSearch(episodeId);
return MapDecisions(decisions);
}
@ -79,7 +82,7 @@ private static List<ReleaseResource> MapDecisions(IEnumerable<DownloadDecision>
{
var release = new ReleaseResource();
release.InjectFrom(downloadDecision.RemoteEpisode.Report);
release.InjectFrom(downloadDecision.RemoteEpisode.Release);
release.InjectFrom(downloadDecision.RemoteEpisode.ParsedEpisodeInfo);
release.InjectFrom(downloadDecision);
release.Rejections = downloadDecision.Rejections.ToList();

View File

@ -12,8 +12,6 @@ public class ReleaseResource : RestResource
public Int32 Age { get; set; }
public Int64 Size { get; set; }
public String Indexer { get; set; }
public String NzbInfoUrl { get; set; }
public String NzbUrl { get; set; }
public String ReleaseGroup { get; set; }
public String Title { get; set; }
public Boolean FullSeason { get; set; }
@ -26,5 +24,9 @@ public class ReleaseResource : RestResource
public Boolean Approved { get; set; }
public Int32 TvRageId { get; set; }
public List<string> Rejections { get; set; }
public DateTime PublishDate { get; set; }
public String CommentUrl { get; set; }
public String DownloadUrl { get; set; }
public String InfoUrl { get; set; }
}
}

View File

@ -17,6 +17,12 @@ public LogModule(ILogService logService)
private PagingResource<LogResource> GetLogs(PagingResource<LogResource> pagingResource)
{
var pageSpec = pagingResource.InjectTo<PagingSpec<Log>>();
if (pageSpec.SortKey == "time")
{
pageSpec.SortKey = "id";
}
return ApplyToPage(_logService.Paged, pageSpec);
}
}

View File

@ -17,9 +17,10 @@ protected override bool Match(ConventionInfo conventionInfo)
protected override object SetValue(ConventionInfo conventionInfo)
{
if (conventionInfo.SourceProp.Type.IsValueType || conventionInfo.SourceProp.Type == typeof(string))
if (conventionInfo.SourceProp.Type == conventionInfo.TargetProp.Type)
return conventionInfo.SourceProp.Value;
if (conventionInfo.SourceProp.Type.IsArray)
{
var array = (Array)conventionInfo.SourceProp.Value;

View File

@ -1,14 +1,14 @@
using System;
using NLog;
using NLog;
using Nancy.Bootstrapper;
using Nancy.Diagnostics;
using NzbDrone.Api.Authentication;
using NzbDrone.Api.ErrorManagement;
using NzbDrone.Api.Extensions;
using NzbDrone.Api.Extensions.Pipelines;
using NzbDrone.Common.Messaging;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.Instrumentation;
using NzbDrone.Core.Lifecycle;
using NzbDrone.Core.Messaging;
using NzbDrone.Core.Messaging.Events;
using TinyIoC;
namespace NzbDrone.Api
@ -21,20 +21,18 @@ public class NancyBootstrapper : TinyIoCNancyBootstrapper
public NancyBootstrapper(TinyIoCContainer tinyIoCContainer)
{
_tinyIoCContainer = tinyIoCContainer;
_logger = LogManager.GetCurrentClassLogger();
_logger = NzbDroneLogger.GetLogger();
}
protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
{
_logger.Info("Starting NzbDrone API");
RegisterPipelines(pipelines);
container.Resolve<DatabaseTarget>().Register();
container.Resolve<IEnableBasicAuthInNancy>().Register(pipelines);
container.Resolve<IMessageAggregator>().PublishEvent(new ApplicationStartedEvent());
container.Resolve<IEventAggregator>().PublishEvent(new ApplicationStartedEvent());
ApplicationPipelines.OnError.AddItemToEndOfPipeline(container.Resolve<NzbDroneErrorPipeline>().HandleException);
}
@ -47,10 +45,8 @@ private void RegisterPipelines(IPipelines pipelines)
{
registerNancyPipeline.Register(pipelines);
}
}
protected override TinyIoCContainer GetApplicationContainer()
{
return _tinyIoCContainer;

View File

@ -91,7 +91,6 @@
<Compile Include="Directories\DirectoryModule.cs" />
<Compile Include="Episodes\EpisodeModule.cs" />
<Compile Include="Episodes\EpisodeResource.cs" />
<Compile Include="Episodes\EpisodeConnection.cs" />
<Compile Include="Extensions\Pipelines\CacheHeaderPipeline.cs" />
<Compile Include="Extensions\Pipelines\GZipPipeline.cs" />
<Compile Include="Extensions\Pipelines\IfModifiedPipeline.cs" />
@ -123,6 +122,8 @@
<Compile Include="Mapping\ValueInjectorExtensions.cs" />
<Compile Include="Missing\MissingModule.cs" />
<Compile Include="Config\NamingSampleResource.cs" />
<Compile Include="NzbDroneRestModuleWithSignalR.cs" />
<Compile Include="ResourceChangeMessage.cs" />
<Compile Include="Notifications\NotificationSchemaModule.cs" />
<Compile Include="Notifications\NotificationModule.cs" />
<Compile Include="Notifications\NotificationResource.cs" />
@ -135,10 +136,6 @@
<Compile Include="REST\RestResource.cs" />
<Compile Include="RootFolders\RootFolderModule.cs" />
<Compile Include="RootFolders\RootFolderResource.cs" />
<Compile Include="RootFolders\RootFolderConnection.cs" />
<Compile Include="Seasons\SeasonModule.cs" />
<Compile Include="Seasons\SeasonResource.cs" />
<Compile Include="Series\SeriesConnection.cs" />
<Compile Include="Series\SeriesResource.cs" />
<Compile Include="Series\SeriesModule.cs" />
<Compile Include="Series\SeriesLookupModule.cs" />
@ -156,11 +153,6 @@
<Compile Include="Qualities\QualitySizeModule.cs" />
<Compile Include="Extensions\ReqResExtensions.cs" />
<Compile Include="Config\SettingsModule.cs" />
<Compile Include="SignalR\BasicResourceConnection.cs" />
<Compile Include="SignalR\NoOpPerformanceCounterManager.cs" />
<Compile Include="SignalR\Serializer.cs" />
<Compile Include="SignalR\SignalrDependencyResolver.cs" />
<Compile Include="SignalR\NzbDronePersistentConnection.cs" />
<Compile Include="System\SystemModule.cs" />
<Compile Include="TinyIoCNancyBootstrapper.cs" />
<Compile Include="Update\UpdateModule.cs" />
@ -183,6 +175,10 @@
<Project>{ff5ee3b6-913b-47ce-9ceb-11c51b4e1205}</Project>
<Name>NzbDrone.Core</Name>
</ProjectReference>
<ProjectReference Include="..\NzbDrone.SignalR\NzbDrone.SignalR.csproj">
<Project>{7c2cc69f-5ca0-4e5c-85cb-983f9f6c3b36}</Project>
<Name>NzbDrone.SignalR</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

View File

@ -1,8 +1,8 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<ConsiderInconclusiveTestsAsPassing>true</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowDynamicCodeContractChecking>false</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
@ -12,9 +12,11 @@
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<UseBuildPlatform />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
<DefaultTestTimeout>5000</DefaultTestTimeout>
<UseBuildConfiguration>Debug</UseBuildConfiguration>
<UseBuildPlatform>x86</UseBuildPlatform>
<ProxyProcessPath></ProxyProcessPath>
<UseCPUArchitecture>x86</UseCPUArchitecture>
<MSTestThreadApartmentState>STA</MSTestThreadApartmentState>
<BuildProcessArchitecture>x86</BuildProcessArchitecture>
</ProjectConfiguration>

View File

@ -9,6 +9,8 @@ namespace NzbDrone.Api
{
public abstract class NzbDroneRestModule<TResource> : RestModule<TResource> where TResource : RestResource, new()
{
protected string Resource { get; private set; }
protected NzbDroneRestModule()
: this(new TResource().ResourceName)
{
@ -17,6 +19,7 @@ protected NzbDroneRestModule()
protected NzbDroneRestModule(string resource)
: base("/api/" + resource.Trim('/'))
{
Resource = resource;
PostValidator.RuleFor(r => r.Id).IsZero();
PutValidator.RuleFor(r => r.Id).ValidId();
}
@ -28,7 +31,7 @@ protected NzbDroneRestModule(string resource)
return model.Id;
}
protected List<TResource> ToListResource<TModel>(Func<IEnumerable<TModel>> function) where TModel : ModelBase, new()
protected List<TResource> ToListResource<TModel>(Func<IEnumerable<TModel>> function) where TModel : class
{
var modelList = function();
return modelList.InjectTo<List<TResource>>();

View File

@ -0,0 +1,56 @@
using NzbDrone.Api.REST;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.Messaging;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.SignalR;
namespace NzbDrone.Api
{
public abstract class NzbDroneRestModuleWithSignalR<TResource, TModel> : NzbDroneRestModule<TResource>, IHandle<ModelEvent<TModel>>
where TResource : RestResource, new()
where TModel : ModelBase
{
private readonly ICommandExecutor _commandExecutor;
protected NzbDroneRestModuleWithSignalR(ICommandExecutor commandExecutor)
{
_commandExecutor = commandExecutor;
}
public void Handle(ModelEvent<TModel> message)
{
if (message.Action == ModelAction.Deleted || message.Action == ModelAction.Sync)
{
BroadcastResourceChange(message.Action);
}
BroadcastResourceChange(message.Action, message.Model.Id);
}
protected void BroadcastResourceChange(ModelAction action, int id)
{
var resource = GetResourceById(id);
var signalRMessage = new SignalRMessage
{
Name = Resource,
Body = new ResourceChangeMessage<TResource>(resource, action)
};
_commandExecutor.PublishCommand(new BroadcastSignalRMessage(signalRMessage));
}
protected void BroadcastResourceChange(ModelAction action)
{
var signalRMessage = new SignalRMessage
{
Name = Resource,
Body = new ResourceChangeMessage<TResource>(action)
};
_commandExecutor.PublishCommand(new BroadcastSignalRMessage(signalRMessage));
}
}
}

View File

@ -61,7 +61,7 @@ protected Action<int> DeleteResource
protected Func<int, TResource> GetResourceById
{
private get { return _getResourceById; }
get { return _getResourceById; }
set
{
_getResourceById = value;

View File

@ -0,0 +1,29 @@
using System;
using NzbDrone.Api.REST;
using NzbDrone.Core.Datastore.Events;
namespace NzbDrone.Api
{
public class ResourceChangeMessage<TResource> where TResource : RestResource
{
public TResource Resource { get; private set; }
public ModelAction Action { get; private set; }
public ResourceChangeMessage(ModelAction action)
{
if (action != ModelAction.Deleted || action != ModelAction.Sync)
{
throw new InvalidOperationException("Resource message without a resource needs to have Delete or Sync as action");
}
Action = action;
}
public ResourceChangeMessage(TResource resource, ModelAction action)
{
Resource = resource;
Action = action;
}
}
}

View File

@ -1,13 +0,0 @@
using NzbDrone.Api.SignalR;
using NzbDrone.Core.RootFolders;
namespace NzbDrone.Api.RootFolders
{
public class RootFolderConnection : BasicResourceConnection<RootFolder>
{
public override string Resource
{
get { return "RootFolder"; }
}
}
}

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using NzbDrone.Core.RootFolders;
using NzbDrone.Api.Mapping;
using NzbDrone.Api.Validation;

View File

@ -1,53 +0,0 @@
using System.Collections.Generic;
using NzbDrone.Api.Mapping;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Seasons
{
public class SeasonModule : NzbDroneRestModule<SeasonResource>
{
private readonly ISeasonService _seasonService;
public SeasonModule(ISeasonService seasonService)
: base("/season")
{
_seasonService = seasonService;
GetResourceAll = GetSeasons;
GetResourceById = GetSeason;
UpdateResource = Update;
Post["/pass"] = x => SetSeasonPass();
}
private List<SeasonResource> GetSeasons()
{
var seriesId = Request.Query.SeriesId;
if (seriesId.HasValue)
{
return ToListResource<Season>(() => _seasonService.GetSeasonsBySeries(seriesId));
}
return ToListResource(() => _seasonService.GetAllSeasons());
}
private SeasonResource GetSeason(int id)
{
return _seasonService.Get(id).InjectTo<SeasonResource>();
}
private void Update(SeasonResource seasonResource)
{
_seasonService.SetMonitored(seasonResource.SeriesId, seasonResource.SeasonNumber, seasonResource.Monitored);
}
private List<SeasonResource> SetSeasonPass()
{
var seriesId = Request.Form.SeriesId;
var seasonNumber = Request.Form.SeasonNumber;
return ToListResource<Season>(() => _seasonService.SetSeasonPass(seriesId, seasonNumber));
}
}
}

View File

@ -1,12 +0,0 @@
using System;
using NzbDrone.Api.REST;
namespace NzbDrone.Api.Seasons
{
public class SeasonResource : RestResource
{
public int SeriesId { get; set; }
public int SeasonNumber { get; set; }
public Boolean Monitored { get; set; }
}
}

View File

@ -1,12 +0,0 @@
using NzbDrone.Api.SignalR;
namespace NzbDrone.Api.Series
{
public class SeriesConnection : BasicResourceConnection<Core.Tv.Series>
{
public override string Resource
{
get { return "/Series"; }
}
}
}

View File

@ -117,7 +117,6 @@ private void LinkSeriesStatistics(SeriesResource resource, SeriesStatistics seri
{
resource.EpisodeCount = seriesStatistics.EpisodeCount;
resource.EpisodeFileCount = seriesStatistics.EpisodeFileCount;
resource.SeasonCount = seriesStatistics.SeasonCount;
resource.NextAiring = seriesStatistics.NextAiring;
}
}

View File

@ -14,7 +14,17 @@ public class SeriesResource : RestResource
//View Only
public String Title { get; set; }
public Int32 SeasonCount { get; set; }
public Int32 SeasonCount
{
get
{
if (Seasons != null) return Seasons.Count;
return 0;
}
}
public Int32 EpisodeCount { get; set; }
public Int32 EpisodeFileCount { get; set; }
public SeriesStatusType Status { get; set; }
@ -26,7 +36,8 @@ public class SeriesResource : RestResource
public List<MediaCover> Images { get; set; }
public String RemotePoster { get; set; }
public List<Season> Seasons { get; set; }
public Int32 Year { get; set; }
//View & Edit
public String Path { get; set; }

View File

@ -1,36 +0,0 @@
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Infrastructure;
using NLog;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Datastore.Events;
namespace NzbDrone.Api.SignalR
{
public abstract class BasicResourceConnection<T> :
NzbDronePersistentConnection,
IHandleAsync<ModelEvent<T>>
where T : ModelBase
{
private readonly Logger _logger;
public BasicResourceConnection()
{
_logger = LogManager.GetCurrentClassLogger();
}
protected override Task OnConnected(IRequest request, string connectionId)
{
_logger.Trace("SignalR client connected. ID:{0}", connectionId);
return base.OnConnected(request, connectionId);
}
public void HandleAsync(ModelEvent<T> message)
{
var context = ((ConnectionManager)GlobalHost.ConnectionManager).GetConnection(GetType());
context.Connection.Broadcast(message);
}
}
}

View File

@ -1,9 +0,0 @@
using Microsoft.AspNet.SignalR;
namespace NzbDrone.Api.SignalR
{
public abstract class NzbDronePersistentConnection : PersistentConnection
{
public abstract string Resource { get; }
}
}

View File

@ -40,6 +40,7 @@ private Response GetStatus()
OsVersion = OsInfo.Version.ToString(),
IsMono = OsInfo.IsMono,
IsLinux = OsInfo.IsLinux,
IsWindows = OsInfo.IsWindows,
Branch = _configFileProvider.Branch,
Authentication = _configFileProvider.AuthenticationEnabled
}.AsResponse();

View File

@ -33,8 +33,6 @@ private List<UpdateResource> GetAvailableUpdate()
public class UpdateResource : RestResource
{
public String Id { get; set; }
[JsonConverter(typeof(Newtonsoft.Json.Converters.VersionConverter))]
public Version Version { get; set; }

View File

@ -1,6 +1,4 @@
using System;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
using System.Text.RegularExpressions;
using FluentValidation;
using FluentValidation.Validators;
@ -27,5 +25,10 @@ public static IRuleBuilderOptions<T, string> IsValidPath<T>(this IRuleBuilder<T,
{
return ruleBuilder.SetValidator(new PathValidator());
}
public static IRuleBuilderOptions<T, string> NotBlank<T>(this IRuleBuilder<T, string> ruleBuilder)
{
return ruleBuilder.SetValidator(new NotNullValidator()).SetValidator(new NotEmptyValidator(""));
}
}
}

View File

@ -2,12 +2,13 @@
using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Download;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Jobs;
using NzbDrone.Core.Lifecycle;
using NzbDrone.Core.Messaging;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Host;
using NzbDrone.Test.Common;
using FluentAssertions;
@ -45,7 +46,6 @@ public void should_resolve_command_executor_by_name()
{
var genericExecutor = typeof(IExecute<>).MakeGenericType(typeof(RssSyncCommand));
var container = MainAppContainerBuilder.BuildContainer(args);
DbFactory.RegisterDatabase(container);
var executor = container.Resolve(genericExecutor);

View File

@ -48,6 +48,23 @@ public void should_be_able_to_update_key()
_cachedString.Find("Key").Should().Be("New");
}
[Test]
public void should_be_able_to_remove_key()
{
_cachedString.Set("Key", "Value");
_cachedString.Remove("Key");
_cachedString.Find("Key").Should().BeNull();
}
[Test]
public void should_be_able_to_remove_non_existing_key()
{
_cachedString.Remove("Key");
}
[Test]
public void should_store_null()
{

View File

@ -23,6 +23,10 @@ public void Setup()
if (_binFolderCopy.Exists)
{
foreach (var file in _binFolderCopy.GetFiles("*", SearchOption.AllDirectories))
{
file.Attributes = FileAttributes.Normal;
}
_binFolderCopy.Delete(true);
}
@ -83,11 +87,7 @@ public void moveFile_should_not_move_overwrite_itself()
[Test]
public void CopyFolder_should_copy_folder()
{
Subject.CopyFolder(_binFolder.FullName, _binFolderCopy.FullName);
VerifyCopy();
}
@ -127,6 +127,22 @@ public void MoveFolder_should_overwrite_existing_folder()
}
[Test]
public void move_read_only_file()
{
var source = GetTestFilePath();
var destination = GetTestFilePath();
Subject.WriteAllText(source, "SourceFile");
Subject.WriteAllText(destination, "DestinationFile");
File.SetAttributes(source, FileAttributes.ReadOnly);
File.SetAttributes(destination, FileAttributes.ReadOnly);
Subject.MoveFile(source, destination);
}
[Test]
@ -139,16 +155,60 @@ public void empty_folder_should_return_folder_modified_date()
[Test]
public void folder_should_return_correct_value_for_last_write()
{
var testFile = Path.Combine(SandboxFolder, "newfile.txt");
var testFile = GetTestFilePath();
TestLogger.Info("Path is: {0}", testFile);
Subject.WriteAllText(testFile, "");
Subject.WriteAllText(testFile, "Test");
Subject.GetLastFolderWrite(SandboxFolder).Should().BeOnOrAfter(DateTime.UtcNow.AddMinutes(-1));
Subject.GetLastFolderWrite(SandboxFolder).Should().BeBefore(DateTime.UtcNow);
}
[Test]
public void should_return_false_for_unlocked_file()
{
var testFile = GetTestFilePath();
Subject.WriteAllText(testFile, new Guid().ToString());
Subject.IsFileLocked(testFile).Should().BeFalse();
}
[Test]
public void should_return_false_for_unlocked_and_readonly_file()
{
var testFile = GetTestFilePath();
Subject.WriteAllText(testFile, new Guid().ToString());
File.SetAttributes(testFile, FileAttributes.ReadOnly);
Subject.IsFileLocked(testFile).Should().BeFalse();
}
[Test]
public void should_return_true_for_unlocked_file()
{
var testFile = GetTestFilePath();
Subject.WriteAllText(testFile, new Guid().ToString());
using (var file = File.OpenWrite(testFile))
{
Subject.IsFileLocked(testFile).Should().BeTrue();
}
}
[Test]
public void should_be_able_to_set_permission_from_parrent()
{
var testFile = GetTestFilePath();
Subject.WriteAllText(testFile, new Guid().ToString());
Subject.InheritFolderPermissions(testFile);
}
[Test]
[Explicit]
public void check_last_write()

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FluentAssertions;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Test.Common;

View File

@ -29,7 +29,7 @@ public void ApplicationPath_should_not_be_empty()
[Test]
public void IsProduction_should_return_false_when_run_within_nunit()
{
RuntimeInfo.IsProduction.Should().BeFalse("Process name is " + Process.GetCurrentProcess().ProcessName);
RuntimeInfo.IsProduction.Should().BeFalse("Process name is " + Process.GetCurrentProcess().ProcessName + " Folder is " + Directory.GetCurrentDirectory());
}
[Test]

View File

@ -1,16 +1,18 @@
using System;
using System.Collections.Generic;
using System.Threading;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.Messaging;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Test.Common;
using FluentAssertions;
namespace NzbDrone.Common.Test.EventingTests
namespace NzbDrone.Common.Test.MessagingTests
{
[TestFixture]
public class MessageAggregatorEventTests : TestBase<MessageAggregator>
public class MessageAggregatorEventTests : TestBase<EventAggregator>
{
private Mock<IHandle<EventA>> HandlerA1;
private Mock<IHandle<EventA>> HandlerA2;
@ -127,7 +129,7 @@ public void should_queue_multiple_async_events()
counter.WaitForAllItems();
counter.MaxThreads.Should().Be(2);
counter.MaxThreads.Should().Be(3);
}
}

View File

@ -67,8 +67,7 @@
<Compile Include="EnsureTest\PathExtensionFixture.cs" />
<Compile Include="EnvironmentTests\StartupArgumentsFixture.cs" />
<Compile Include="EnvironmentTests\EnvironmentProviderTest.cs" />
<Compile Include="EventingTests\MessageAggregatorCommandTests.cs" />
<Compile Include="EventingTests\MessageAggregatorEventTests.cs" />
<Compile Include="MessagingTests\MessageAggregatorEventTests.cs" />
<Compile Include="ReflectionExtensions.cs" />
<Compile Include="PathExtensionFixture.cs" />
<Compile Include="DiskProviderTests\DiskProviderFixture.cs" />

View File

@ -2,7 +2,7 @@
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>true</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowDynamicCodeContractChecking>false</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
@ -12,11 +12,11 @@
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration></UseBuildConfiguration>
<UseBuildPlatform></UseBuildPlatform>
<DefaultTestTimeout>5000</DefaultTestTimeout>
<UseBuildConfiguration>Debug</UseBuildConfiguration>
<UseBuildPlatform>x86</UseBuildPlatform>
<ProxyProcessPath></ProxyProcessPath>
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
<UseCPUArchitecture>x86</UseCPUArchitecture>
<MSTestThreadApartmentState>STA</MSTestThreadApartmentState>
<BuildProcessArchitecture>x86</BuildProcessArchitecture>
<IgnoredTests>
@ -26,11 +26,35 @@
<RegexTestSelector>
<RegularExpression>NzbDrone\.Common\.Test\.EventingTests\.ServiceNameFixture\..*</RegularExpression>
</RegexTestSelector>
<RegexTestSelector>
<RegularExpression>NzbDrone\.Common\.Test\.ProcessProviderTests\..*</RegularExpression>
</RegexTestSelector>
<RegexTestSelector>
<RegularExpression>NzbDrone\.Common\.Test\.ServiceFactoryFixture\..*</RegularExpression>
</RegexTestSelector>
<NamedTestSelector>
<TestName>NzbDrone.Common.Test.ProcessProviderTests.ToString_on_new_processInfo</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>NzbDrone.Common.Test.ProcessProviderTests.Should_be_able_to_start_process</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>NzbDrone.Common.Test.ProcessProviderTests.kill_all_should_kill_all_process_with_name</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>NzbDrone.Common.Test.ProcessProviderTests.GetProcessById_should_return_null_for_invalid_process(9999)</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>NzbDrone.Common.Test.ProcessProviderTests.GetProcessById_should_return_null_for_invalid_process(-1)</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>NzbDrone.Common.Test.ProcessProviderTests.GetProcessById_should_return_null_for_invalid_process(0)</TestName>
</NamedTestSelector>
<RegexTestSelector>
<RegularExpression>NzbDrone\.Common\.Test\.ServiceProviderTests\..*</RegularExpression>
</RegexTestSelector>
<NamedTestSelector>
<TestName>NzbDrone.Common.Test.DiskProviderTests.DiskProviderFixture.folder_should_return_correct_value_for_last_write</TestName>
</NamedTestSelector>
<RegexTestSelector>
<RegularExpression>NzbDrone\.Common\.Test\.DiskProviderTests\.DiskProviderFixture\..*</RegularExpression>
</RegexTestSelector>
</IgnoredTests>
</ProjectConfiguration>

View File

@ -126,17 +126,16 @@ public void get_actual_casing_should_return_actual_casing_for_local_file_in_wind
}
[Test]
public void get_actual_casing_should_return_actual_casing_for_local_dir_in_windows()
{
WindowsOnly();
var path = Directory.GetCurrentDirectory();
var path = Directory.GetCurrentDirectory().Replace("c:\\","C:\\");
path.ToUpper().GetActualCasing().Should().Be(path);
path.ToLower().GetActualCasing().Should().Be(path);
}
[Test]
public void get_actual_casing_should_return_original_value_in_linux()
{

View File

@ -73,7 +73,7 @@ public void kill_all_should_kill_all_process_with_name()
var dummy1 = StartDummyProcess();
var dummy2 = StartDummyProcess();
Subject.KillAll(dummy1.ProcessName);
Subject.KillAll(DummyApp.DUMMY_PROCCESS_NAME);
dummy1.HasExited.Should().BeTrue();
dummy2.HasExited.Should().BeTrue();

View File

@ -2,8 +2,9 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.Lifecycle;
using NzbDrone.Core.Messaging;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Host;
using NzbDrone.Test.Common;

View File

@ -28,7 +28,6 @@ public ICached<T> GetCache<T>(Type host)
return GetCache<T>(host, host.FullName);
}
public void Clear()
{
_cache.Clear();

View File

@ -61,6 +61,12 @@ public T Find(string key)
return value.Object;
}
public void Remove(string key)
{
CacheItem value;
_store.TryRemove(key, out value);
}
public T Get(string key, Func<T> function, TimeSpan? lifeTime = null)
{
Ensure.That(() => key).IsNotNullOrWhiteSpace();
@ -81,7 +87,6 @@ public T Get(string key, Func<T> function, TimeSpan? lifeTime = null)
return value;
}
public void Clear()
{
_store.Clear();

View File

@ -13,6 +13,7 @@ public interface ICached<T> : ICached
void Set(string key, T value, TimeSpan? lifetime = null);
T Get(string key, Func<T> function, TimeSpan? lifeTime = null);
T Find(string key);
void Remove(string key);
ICollection<T> Values { get; }
}

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
@ -8,12 +7,12 @@
using NLog;
using NzbDrone.Common.EnsureThat;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation;
namespace NzbDrone.Common
{
public interface IDiskProvider
{
HashSet<string> SpecialFolders { get; }
DateTime GetLastFolderWrite(string path);
DateTime GetLastFileWrite(string path);
void EnsureFolder(string path);
@ -24,8 +23,8 @@ public interface IDiskProvider
string[] GetFiles(string path, SearchOption searchOption);
long GetFolderSize(string path);
long GetFileSize(string path);
String CreateFolder(string path);
void CopyFolder(string source, string target);
void CreateFolder(string path);
void CopyFolder(string source, string destination);
void MoveFolder(string source, string destination);
void DeleteFile(string path);
void MoveFile(string source, string destination);
@ -36,11 +35,12 @@ public interface IDiskProvider
void WriteAllText(string filename, string contents);
void FileSetLastWriteTimeUtc(string path, DateTime dateTime);
void FolderSetLastWriteTimeUtc(string path, DateTime dateTime);
bool IsFileLocked(FileInfo file);
bool IsFileLocked(string path);
string GetPathRoot(string path);
void SetPermissions(string filename, WellKnownSidType accountSid, FileSystemRights rights, AccessControlType controlType);
bool IsParent(string parentPath, string childPath);
FileAttributes GetFileAttributes(string path);
void EmptyFolder(string path);
}
public class DiskProvider : IDiskProvider
@ -58,15 +58,7 @@ static extern bool GetDiskFreeSpaceEx(string lpDirectoryName,
out ulong lpTotalNumberOfBytes,
out ulong lpTotalNumberOfFreeBytes);
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public HashSet<string> SpecialFolders
{
get
{
return new HashSet<string> { "$recycle.bin", "system volume information", "recycler" };
}
}
private static readonly Logger Logger = NzbDroneLogger.GetLogger();
public DateTime GetLastFolderWrite(string path)
{
@ -93,7 +85,9 @@ public DateTime GetLastFileWrite(string path)
Ensure.That(() => path).IsValidPath();
if (!FileExists(path))
{
throw new FileNotFoundException("File doesn't exist: " + path);
}
return new FileInfo(path).LastWriteTimeUtc;
}
@ -154,25 +148,26 @@ public long GetFileSize(string path)
Ensure.That(() => path).IsValidPath();
if (!FileExists(path))
{
throw new FileNotFoundException("File doesn't exist: " + path);
}
var fi = new FileInfo(path);
return fi.Length;
}
public String CreateFolder(string path)
public void CreateFolder(string path)
{
Ensure.That(() => path).IsValidPath();
return Directory.CreateDirectory(path).FullName;
Directory.CreateDirectory(path);
}
public void CopyFolder(string source, string target)
public void CopyFolder(string source, string destination)
{
Ensure.That(() => source).IsValidPath();
Ensure.That(() => target).IsValidPath();
Ensure.That(() => destination).IsValidPath();
TransferFolder(source, target, TransferAction.Copy);
TransferFolder(source, destination, TransferAction.Copy);
}
public void MoveFolder(string source, string destination)
@ -183,7 +178,7 @@ public void MoveFolder(string source, string destination)
try
{
TransferFolder(source, destination, TransferAction.Move);
Directory.Delete(source, true);
DeleteFolder(source, true);
}
catch (Exception e)
{
@ -238,8 +233,10 @@ private void TransferFolder(string source, string target, TransferAction transfe
public void DeleteFile(string path)
{
Ensure.That(() => path).IsValidPath();
Logger.Trace("Deleting file: {0}", path);
RemoveReadOnly(path);
File.Delete(path);
}
@ -259,6 +256,7 @@ public void MoveFile(string source, string destination)
DeleteFile(destination);
}
RemoveReadOnly(source);
File.Move(source, destination);
}
@ -273,10 +271,20 @@ public void InheritFolderPermissions(string filename)
{
Ensure.That(() => filename).IsValidPath();
try
{
var fs = File.GetAccessControl(filename);
fs.SetAccessRuleProtection(false, false);
File.SetAccessControl(filename, fs);
}
catch (NotImplementedException)
{
if (!OsInfo.IsLinux)
{
throw;
}
}
}
public long? GetAvailableSpace(string path)
{
@ -347,11 +355,10 @@ public string ReadAllText(string filePath)
public void WriteAllText(string filename, string contents)
{
Ensure.That(() => filename).IsValidPath();
RemoveReadOnly(filename);
File.WriteAllText(filename, contents);
}
public void FileSetLastWriteTimeUtc(string path, DateTime dateTime)
{
Ensure.That(() => path).IsValidPath();
@ -366,26 +373,19 @@ public void FolderSetLastWriteTimeUtc(string path, DateTime dateTime)
Directory.SetLastWriteTimeUtc(path, dateTime);
}
public bool IsFileLocked(FileInfo file)
public bool IsFileLocked(string file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None);
using (File.Open(file, FileMode.Open, FileAccess.Read, FileShare.None))
{
return false;
}
}
catch (IOException)
{
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
public string GetPathRoot(string path)
@ -441,9 +441,34 @@ public bool IsParent(string parentPath, string childPath)
return false;
}
private static void RemoveReadOnly(string path)
{
if (File.Exists(path))
{
var newAttributes = File.GetAttributes(path) & ~(FileAttributes.ReadOnly);
File.SetAttributes(path, newAttributes);
}
}
public FileAttributes GetFileAttributes(string path)
{
return File.GetAttributes(path);
}
public void EmptyFolder(string path)
{
Ensure.That(() => path).IsValidPath();
foreach (var file in GetFiles(path, SearchOption.TopDirectoryOnly))
{
DeleteFile(file);
}
foreach (var directory in GetDirectories(path))
{
DeleteFolder(directory, true);
}
}
}
}

View File

@ -1,5 +1,4 @@
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using NzbDrone.Common.EnsureThat.Resources;
using NzbDrone.Common.EnvironmentInfo;

View File

@ -4,6 +4,7 @@
using System.Security.AccessControl;
using System.Security.Principal;
using NLog;
using NzbDrone.Common.Instrumentation;
namespace NzbDrone.Common.EnvironmentInfo
{
@ -30,7 +31,7 @@ public AppFolderInfo(IDiskProvider diskProvider, IStartupArguments startupArgume
DATA_SPECIAL_FOLDER = Environment.SpecialFolder.ApplicationData;
}
_logger = LogManager.GetCurrentClassLogger();
_logger = NzbDroneLogger.GetLogger(this);
if (startupArguments.Args.ContainsKey(StartupArguments.APPDATA))
{

View File

@ -2,7 +2,6 @@
using System.Diagnostics;
using System.IO;
using System.Security.Principal;
using System.ServiceProcess;
using NLog;
namespace NzbDrone.Common.EnvironmentInfo
@ -65,7 +64,9 @@ private static bool InternalIsProduction()
if (lowerProcessName.Contains("jetbrain")) return false;
if (lowerProcessName.Contains("resharper")) return false;
if (Directory.GetCurrentDirectory().ToLower().Contains("teamcity")) return false;
string lowerCurrentDir = Directory.GetCurrentDirectory().ToLower();
if (lowerCurrentDir.Contains("teamcity")) return false;
if (lowerCurrentDir.StartsWith("/run/")) return false;
return true;
}

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
namespace NzbDrone.Common.EnvironmentInfo
{
@ -17,14 +16,6 @@ public class StartupArguments : IStartupArguments
public const string UNINSTALL_SERVICE = "u";
public const string HELP = "?";
static StartupArguments()
{
if (RuntimeInfo.IsProduction)
{
Instance = new StartupArguments("");
}
}
public StartupArguments(params string[] args)
{
Flags = new HashSet<string>();
@ -45,13 +36,9 @@ public StartupArguments(params string[] args)
Flags.Add(flag);
}
}
Instance = this;
}
public HashSet<string> Flags { get; private set; }
public Dictionary<string, string> Args { get; private set; }
public static IStartupArguments Instance { get; private set; }
}
}

View File

@ -2,8 +2,6 @@
namespace NzbDrone.Common.Exceptions
{
public abstract class NzbDroneException : ApplicationException
{
protected NzbDroneException(string message, params object[] args)
@ -17,5 +15,16 @@ protected NzbDroneException(string message)
{
}
protected NzbDroneException(string message, Exception innerException, params object[] args)
: base(string.Format(message, args), innerException)
{
}
protected NzbDroneException(string message, Exception innerException)
: base(message, innerException)
{
}
}
}

View File

@ -1,5 +1,4 @@
using System;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
@ -34,31 +33,9 @@ public static string CalculateCrc(string input)
return String.Format("{0:x8}", mCrc);
}
public static string GenerateUserId()
public static string GenerateCommandId()
{
return GenerateId("u");
}
public static string GenerateAppId()
{
return GenerateId("a");
}
public static string GenerateApiToken()
{
return Guid.NewGuid().ToString().Replace("-", "");
}
public static string GenerateSecurityToken(int length)
{
var byteSize = (length / 4) * 3;
var linkBytes = new byte[byteSize];
var rngCrypto = new RNGCryptoServiceProvider();
rngCrypto.GetBytes(linkBytes);
var base64String = Convert.ToBase64String(linkBytes);
return base64String;
return GenerateId("c");
}
private static string GenerateId(string prefix)

View File

@ -1,26 +0,0 @@
using System.IO;
using System.Text;
using NLog;
using NLog.Config;
using NLog.LayoutRenderers;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common.Instrumentation
{
[ThreadAgnostic]
[LayoutRenderer("appLog")]
public class ApplicationLogLayoutRenderer : LayoutRenderer
{
private readonly string _appData;
public ApplicationLogLayoutRenderer()
{
_appData = Path.Combine(new AppFolderInfo(new DiskProvider(), StartupArguments.Instance ).GetLogFolder(), "nzbdrone.txt");
}
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
builder.Append(_appData);
}
}
}

View File

@ -1,19 +0,0 @@
using System.IO;
using System.Text;
using NLog;
using NLog.Config;
using NLog.LayoutRenderers;
namespace NzbDrone.Common.Instrumentation
{
[ThreadAgnostic]
[LayoutRenderer("dirSeparator")]
public class DirSeparatorLayoutRenderer : LayoutRenderer
{
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
builder.Append(Path.DirectorySeparatorChar);
}
}
}

View File

@ -4,7 +4,6 @@
using Exceptron.Client.Configuration;
using NLog;
using NLog.Common;
using NLog.Config;
using NLog.Layouts;
using NLog.Targets;
using NzbDrone.Common.EnvironmentInfo;
@ -23,19 +22,6 @@ public class ExceptronTarget : Target
/// </summary>
public IExceptronClient ExceptronClient { get; internal set; }
private static ExceptronTarget _instance = new ExceptronTarget();
public static void Register()
{
var rule = new LoggingRule("*", LogLevel.Warn, _instance);
LogManager.Configuration.AddTarget("ExceptronTarget", _instance);
LogManager.Configuration.LoggingRules.Add(rule);
LogManager.ConfigurationReloaded += (sender, args) => Register();
LogManager.ReconfigExistingLoggers();
}
protected override void InitializeTarget()
{
var config = new ExceptronConfiguration

View File

@ -6,12 +6,9 @@ namespace NzbDrone.Common.Instrumentation
{
public static class GlobalExceptionHandlers
{
private static readonly Logger Logger = LogManager.GetLogger("Global");
private static readonly Logger Logger = NzbDroneLogger.GetLogger();
public static void Register()
{
ExceptronTarget.Register();
AppDomain.CurrentDomain.UnhandledException += ((s, e) => AppDomainException(e.ExceptionObject as Exception));
TaskScheduler.UnobservedTaskException += ((s, e) => TaskException(e.Exception));
}
@ -24,6 +21,15 @@ private static void TaskException(Exception exception)
private static void AppDomainException(Exception exception)
{
if (exception == null) return;
if (exception is NullReferenceException &&
exception.ToString().Contains("Microsoft.AspNet.SignalR.Transports.TransportHeartbeat.ProcessServerCommand"))
{
Logger.Warn("SignalR Heartbeat error.");
return;
}
Console.WriteLine("EPIC FAIL: {0}", exception);
Logger.FatalException("EPIC FAIL: " + exception.Message, exception);
}

View File

@ -13,7 +13,6 @@ public static string GetHash(this LogEventInfo logEvent)
return HashUtil.CalculateCrc(hashSeed);
}
public static string GetFormattedMessage(this LogEventInfo logEvent)
{
var message = logEvent.FormattedMessage;

View File

@ -0,0 +1,127 @@
using System;
using System.IO;
using NLog;
using NLog.Config;
using NLog.Targets;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common.Instrumentation
{
public static class LogTargets
{
public static void Register(IStartupArguments startupArguments, bool updateApp, bool inConsole)
{
var appFolderInfo = new AppFolderInfo(new DiskProvider(), startupArguments);
LogManager.Configuration = new LoggingConfiguration();
RegisterExceptron();
if (updateApp)
{
RegisterLoggly();
RegisterUpdateFile(appFolderInfo);
}
else
{
if (inConsole && (OsInfo.IsLinux || new RuntimeInfo(null).IsUserInteractive))
{
RegisterConsole();
}
RegisterAppFile(appFolderInfo);
}
LogManager.ReconfigExistingLoggers();
}
private static void RegisterConsole()
{
var level = LogLevel.Trace;
if (RuntimeInfo.IsProduction)
{
level = LogLevel.Info;
}
var coloredConsoleTarget = new ColoredConsoleTarget();
coloredConsoleTarget.Name = "consoleLogger";
coloredConsoleTarget.Layout = "[${level}] ${logger}: ${message} ${onexception:inner=${newline}${newline}${exception:format=ToString}${newline}}";
var loggingRule = new LoggingRule("*", level, coloredConsoleTarget);
LogManager.Configuration.AddTarget("console", coloredConsoleTarget);
LogManager.Configuration.LoggingRules.Add(loggingRule);
}
const string FileLogLayout = @"${date:format=yy-M-d HH\:mm\:ss.f}|${level}|${logger}|${message}${onexception:inner=${newline}${newline}${exception:format=ToString}${newline}}";
private static void RegisterAppFile(IAppFolderInfo appFolderInfo)
{
var fileTarget = new FileTarget();
fileTarget.Name = "rollingFileLogger";
fileTarget.FileName = Path.Combine(appFolderInfo.GetLogFolder(), "nzbdrone.txt");
fileTarget.AutoFlush = true;
fileTarget.KeepFileOpen = false;
fileTarget.ConcurrentWrites = false;
fileTarget.ConcurrentWriteAttemptDelay = 50;
fileTarget.ConcurrentWriteAttempts = 10;
fileTarget.ArchiveAboveSize = 1024000;
fileTarget.MaxArchiveFiles = 5;
fileTarget.EnableFileDelete = true;
fileTarget.ArchiveNumbering = ArchiveNumberingMode.Rolling;
fileTarget.Layout = FileLogLayout;
var loggingRule = new LoggingRule("*", LogLevel.Info, fileTarget);
LogManager.Configuration.AddTarget("appfile", fileTarget);
LogManager.Configuration.LoggingRules.Add(loggingRule);
}
private static void RegisterUpdateFile(IAppFolderInfo appFolderInfo)
{
var fileTarget = new FileTarget();
fileTarget.Name = "updateFileLogger";
fileTarget.FileName = Path.Combine(appFolderInfo.GetUpdateLogFolder(), DateTime.Now.ToString("yy.MM.d-HH.mm") + ".txt");
fileTarget.AutoFlush = true;
fileTarget.KeepFileOpen = false;
fileTarget.ConcurrentWrites = false;
fileTarget.ConcurrentWriteAttemptDelay = 50;
fileTarget.ConcurrentWriteAttempts = 100;
fileTarget.Layout = FileLogLayout;
var loggingRule = new LoggingRule("*", LogLevel.Trace, fileTarget);
LogManager.Configuration.AddTarget("updateFile", fileTarget);
LogManager.Configuration.LoggingRules.Add(loggingRule);
}
private static void RegisterExceptron()
{
var exceptronTarget = new ExceptronTarget();
var rule = new LoggingRule("*", LogLevel.Warn, exceptronTarget);
LogManager.Configuration.AddTarget("ExceptronTarget", exceptronTarget);
LogManager.Configuration.LoggingRules.Add(rule);
}
private static void RegisterLoggly()
{
var logglyTarger = new LogglyTarget();
var rule = new LoggingRule("*", LogLevel.Trace, logglyTarger);
LogManager.Configuration.AddTarget("LogglyLogger", logglyTarger);
LogManager.Configuration.LoggingRules.Add(rule);
}
}
}

View File

@ -1,6 +1,5 @@
using System.Collections.Generic;
using NLog;
using NLog.Config;
using NLog.Layouts;
using NLog.Targets;
using NzbDrone.Common.EnvironmentInfo;
@ -13,16 +12,10 @@ public class LogglyTarget : TargetWithLayout
{
private Logger _logger;
public void Register(LogLevel minLevel)
public LogglyTarget()
{
Layout = new SimpleLayout("${callsite:className=false:fileName=false:includeSourcePath=false:methodName=true}");
var rule = new LoggingRule("*", minLevel, this);
LogManager.Configuration.AddTarget("LogglyLogger", this);
LogManager.Configuration.LoggingRules.Add(rule);
LogManager.ConfigurationReloaded += (sender, args) => Register(minLevel);
LogManager.ReconfigExistingLoggers();
}
protected override void InitializeTarget()

View File

@ -0,0 +1,42 @@
using System;
using System.Diagnostics;
using NLog;
namespace NzbDrone.Common.Instrumentation
{
public static class NzbDroneLogger
{
public static Logger GetLogger()
{
string loggerName;
Type declaringType;
int framesToSkip = 1;
do
{
var frame = new StackFrame(framesToSkip, false);
var method = frame.GetMethod();
declaringType = method.DeclaringType;
if (declaringType == null)
{
loggerName = method.Name;
break;
}
framesToSkip++;
loggerName = declaringType.Name;
} while (declaringType.Module.Name.Equals("mscorlib.dll", StringComparison.OrdinalIgnoreCase));
return LogManager.GetLogger(loggerName);
}
public static Logger GetLogger(object obj)
{
return LogManager.GetLogger(obj.GetType().Name);
}
public static Logger GetLogger<T>()
{
return LogManager.GetLogger(typeof(T).Name);
}
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.IO;
using System.Text;
using NLog;
using NLog.Config;
using NLog.LayoutRenderers;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common.Instrumentation
{
[ThreadAgnostic]
[LayoutRenderer("updateLog")]
public class UpdateLogLayoutRenderer : LayoutRenderer
{
private readonly string _appData;
public UpdateLogLayoutRenderer()
{
_appData = Path.Combine(new AppFolderInfo(new DiskProvider(), StartupArguments.Instance).GetUpdateLogFolder(), DateTime.Now.ToString("yy.MM.d-HH.mm") + ".txt");
}
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
builder.Append(_appData);
}
}
}

View File

@ -1,12 +0,0 @@
namespace NzbDrone.Common.Messaging
{
public class CommandCompletedEvent : IEvent
{
public ICommand Command { get; private set; }
public CommandCompletedEvent(ICommand command)
{
Command = command;
}
}
}

View File

@ -1,16 +0,0 @@
using System;
namespace NzbDrone.Common.Messaging
{
public class CommandFailedEvent : IEvent
{
public ICommand Command { get; private set; }
public Exception Exception { get; private set; }
public CommandFailedEvent(ICommand command, Exception exception)
{
Command = command;
Exception = exception;
}
}
}

View File

@ -1,12 +0,0 @@
namespace NzbDrone.Common.Messaging
{
public class CommandExecutedEvent : IEvent
{
public ICommand Command { get; private set; }
public CommandExecutedEvent(ICommand command)
{
Command = command;
}
}
}

View File

@ -1,6 +0,0 @@
namespace NzbDrone.Common.Messaging
{
public interface ICommand : IMessage
{
}
}

View File

@ -1,4 +1,4 @@
namespace NzbDrone.Common.Messaging
namespace NzbDrone.Common.Messaging
{
public interface IEvent : IMessage
{

View File

@ -1,12 +0,0 @@
namespace NzbDrone.Common.Messaging
{
/// <summary>
/// Enables loosely-coupled publication of events.
/// </summary>
public interface IMessageAggregator
{
void PublishEvent<TEvent>(TEvent @event) where TEvent : class, IEvent;
void PublishCommand<TCommand>(TCommand command) where TCommand : class, ICommand;
void PublishCommand(string commandType);
}
}

View File

@ -1,17 +0,0 @@
using System;
namespace NzbDrone.Common.Messaging
{
public static class MessageExtensions
{
public static string GetExecutorName(this Type commandType)
{
if (!typeof(ICommand).IsAssignableFrom(commandType))
{
throw new ArgumentException("commandType must implement ICommand");
}
return string.Format("I{0}Executor", commandType.Name);
}
}
}

View File

@ -1,13 +0,0 @@
namespace NzbDrone.Common.Messaging
{
public class TestCommand : ICommand
{
public TestCommand()
{
Duration = 4000;
}
public int Duration { get; set; }
}
}

View File

@ -1,12 +0,0 @@
using System.Threading;
namespace NzbDrone.Common.Messaging
{
public class TestCommandExecutor : IExecute<TestCommand>
{
public void Execute(TestCommand message)
{
Thread.Sleep(message.Duration);
}
}
}

View File

@ -41,7 +41,7 @@
</Reference>
<Reference Include="Loggly, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\loggly-csharp.2.2\lib\Loggly.dll</HintPath>
<HintPath>..\packages\loggly-csharp.2.3\lib\net35\Loggly.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
@ -92,6 +92,11 @@
<Compile Include="IEnumerableExtensions.cs" />
<Compile Include="Instrumentation\GlobalExceptionHandlers.cs" />
<Compile Include="Instrumentation\ExceptronTarget.cs" />
<Compile Include="Instrumentation\LogEventExtensions.cs" />
<Compile Include="Instrumentation\NzbDroneLogger.cs" />
<Compile Include="Instrumentation\LogTargets.cs" />
<Compile Include="Messaging\IEvent.cs" />
<Compile Include="Messaging\IMessage.cs" />
<Compile Include="PathEqualityComparer.cs" />
<Compile Include="Services.cs" />
<Compile Include="TPL\LimitedConcurrencyLevelTaskScheduler.cs" />
@ -99,23 +104,8 @@
<Compile Include="StringExtensions.cs" />
<Compile Include="EnsureThat\TypeParam.cs" />
<Compile Include="HashUtil.cs" />
<Compile Include="Instrumentation\ApplicationLogLayoutRenderer.cs" />
<Compile Include="Instrumentation\DirSeparatorLayoutRenderer.cs" />
<Compile Include="Instrumentation\LogEventExtensions.cs" />
<Compile Include="Instrumentation\LogglyTarget.cs" />
<Compile Include="Instrumentation\UpdateLogLayoutRenderer.cs" />
<Compile Include="Serializer\Json.cs" />
<Compile Include="Messaging\CommandCompletedEvent.cs" />
<Compile Include="Messaging\CommandStartedEvent.cs" />
<Compile Include="Messaging\CommandFailedEvent.cs" />
<Compile Include="Messaging\IExecute.cs" />
<Compile Include="Messaging\ICommand.cs" />
<Compile Include="Messaging\IMessage.cs" />
<Compile Include="Messaging\IProcessMessage.cs" />
<Compile Include="Messaging\MessageAggregator.cs" />
<Compile Include="Messaging\IEvent.cs" />
<Compile Include="Messaging\IMessageAggregator.cs" />
<Compile Include="Messaging\IHandle.cs" />
<Compile Include="Expansive\CircularReferenceException.cs" />
<Compile Include="Expansive\Expansive.cs" />
<Compile Include="Expansive\PatternStyle.cs" />
@ -123,9 +113,6 @@
<Compile Include="Expansive\TreeNode.cs" />
<Compile Include="Expansive\TreeNodeList.cs" />
<Compile Include="Instrumentation\VersionLayoutRenderer.cs" />
<Compile Include="Messaging\MessageExtensions.cs" />
<Compile Include="Messaging\TestCommand.cs" />
<Compile Include="Messaging\TestCommandExecutor.cs" />
<Compile Include="Reflection\ReflectionExtensions.cs" />
<Compile Include="ServiceFactory.cs" />
<Compile Include="HttpProvider.cs" />

View File

@ -1,8 +1,8 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<ConsiderInconclusiveTestsAsPassing>true</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowDynamicCodeContractChecking>false</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
@ -12,8 +12,11 @@
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
<DefaultTestTimeout>5000</DefaultTestTimeout>
<UseBuildConfiguration>Debug</UseBuildConfiguration>
<UseBuildPlatform>x86</UseBuildPlatform>
<ProxyProcessPath></ProxyProcessPath>
<UseCPUArchitecture>x86</UseCPUArchitecture>
<MSTestThreadApartmentState>STA</MSTestThreadApartmentState>
<BuildProcessArchitecture>x86</BuildProcessArchitecture>
</ProjectConfiguration>

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common

View File

@ -6,6 +6,7 @@
using System.Linq;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Common.Model;
namespace NzbDrone.Common
@ -26,7 +27,7 @@ public interface IProcessProvider
public class ProcessProvider : IProcessProvider
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly Logger Logger = NzbDroneLogger.GetLogger();
public const string NZB_DRONE_PROCESS_NAME = "NzbDrone";
public const string NZB_DRONE_CONSOLE_PROCESS_NAME = "NzbDrone.Console";
@ -212,7 +213,7 @@ private static ProcessInfo ConvertToProcessInfo(Process process)
return new ProcessInfo
{
Id = process.Id,
StartPath = process.MainModule.FileName,
StartPath = GetExeFileName(process),
Name = process.ProcessName
};
}
@ -224,6 +225,17 @@ private static ProcessInfo ConvertToProcessInfo(Process process)
return null;
}
private static string GetExeFileName(Process process)
{
if (process.MainModule.FileName != "mono.exe")
{
return process.MainModule.FileName;
}
return process.Modules.Cast<ProcessModule>().FirstOrDefault(module => module.ModuleName.ToLower().EndsWith(".exe")).FileName;
}
private void Kill(int processId)
{
var process = Process.GetProcesses().FirstOrDefault(p => p.Id == processId);

View File

@ -3,12 +3,13 @@
using System.Security.Cryptography.X509Certificates;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation;
namespace NzbDrone.Common.Security
{
public static class IgnoreCertErrorPolicy
{
private static readonly Logger Logger = LogManager.GetLogger("CertPolicy");
private static readonly Logger Logger = NzbDroneLogger.GetLogger();
public static void Register()
{

View File

@ -5,6 +5,7 @@
using System.Linq;
using System.ServiceProcess;
using NLog;
using NzbDrone.Common.Instrumentation;
namespace NzbDrone.Common
{
@ -25,7 +26,7 @@ public class ServiceProvider : IServiceProvider
{
public const string NZBDRONE_SERVICE_NAME = "NzbDrone";
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly Logger Logger = NzbDroneLogger.GetLogger();
public virtual bool ServiceExist(string name)
{

View File

@ -1,11 +1,12 @@
using System.Threading.Tasks;
using NLog;
using NzbDrone.Common.Instrumentation;
namespace NzbDrone.Common.TPL
{
public static class TaskExtensions
{
private static readonly Logger Logger = LogManager.GetLogger("TaskExtensions");
private static readonly Logger Logger = NzbDroneLogger.GetLogger();
public static Task LogExceptions(this Task task)
{

View File

@ -70,7 +70,6 @@ namespace TinyIoC
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="loggly-csharp" version="2.2" targetFramework="net40" />
<package id="loggly-csharp" version="2.3" targetFramework="net40" />
<package id="Newtonsoft.Json" version="5.0.6" targetFramework="net40" />
<package id="NLog" version="2.0.1.2" targetFramework="net40" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net40" />

View File

@ -2,23 +2,29 @@
using System.Threading;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Host;
namespace NzbDrone.Console
{
public static class ConsoleApp
{
private static readonly Logger Logger = NzbDroneLogger.GetLogger();
public static void Main(string[] args)
{
try
{
Bootstrap.Start(new StartupArguments(args), new ConsoleAlerts());
var startupArgs = new StartupArguments(args);
LogTargets.Register(startupArgs, false, true);
Bootstrap.Start(startupArgs, new ConsoleAlerts());
}
catch (TerminateApplicationException)
{
}
catch (Exception e)
{
Logger.FatalException("EPIC FAIL!", e);
System.Console.ReadLine();
}

View File

@ -3,7 +3,6 @@
using NUnit.Framework;
using Newtonsoft.Json;
using NzbDrone.Common;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.Test.Framework;
@ -13,7 +12,7 @@ namespace NzbDrone.Core.Test.DataAugmentationFixture.Scene
public class SceneMappingProxyFixture : CoreTest<SceneMappingProxy>
{
private const string SCENE_MAPPING_URL = "http://services.nzbdrone.com/SceneMapping/Active";
private const string SCENE_MAPPING_URL = "http://services.nzbdrone.com/v1/SceneMapping";
[Test]
public void fetch_should_return_list_of_mappings()
@ -31,7 +30,6 @@ public void fetch_should_return_list_of_mappings()
mappings.Should().NotContain(c => c.TvdbId == 0);
}
[Test]
public void should_throw_on_server_error()
{

View File

@ -1,84 +0,0 @@
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Datastore.Migration.Framework;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.Datastore
{
[TestFixture]
public class SQLiteMigrationHelperFixture : DbTest
{
private SQLiteMigrationHelper _subject;
[SetUp]
public void SetUp()
{
_subject = Mocker.Resolve<SQLiteMigrationHelper>();
}
[Test]
public void should_parse_existing_columns()
{
var columns = _subject.GetColumns("Series");
columns.Should().NotBeEmpty();
columns.Values.Should().NotContain(c => string.IsNullOrWhiteSpace(c.Name));
columns.Values.Should().NotContain(c => string.IsNullOrWhiteSpace(c.Schema));
}
[Test]
public void should_create_table_from_column_list()
{
var columns = _subject.GetColumns("Series");
columns.Remove("Title");
_subject.CreateTable("Series_New", columns.Values);
var newColumns = _subject.GetColumns("Series_New");
newColumns.Values.Should().HaveSameCount(columns.Values);
newColumns.Should().NotContainKey("Title");
}
[Test]
public void should_get_zero_count_on_empty_table()
{
_subject.GetRowCount("Series").Should().Be(0);
}
[Test]
public void should_be_able_to_transfer_empty_tables()
{
var columns = _subject.GetColumns("Series");
columns.Remove("Title");
_subject.CreateTable("Series_New", columns.Values);
_subject.CopyData("Series", "Series_New", columns.Values);
}
[Test]
public void should_transfer_table_with_data()
{
var originalEpisodes = Builder<Episode>.CreateListOfSize(10).BuildListOfNew();
Mocker.Resolve<EpisodeRepository>().InsertMany(originalEpisodes);
var columns = _subject.GetColumns("Episodes");
columns.Remove("Title");
_subject.CreateTable("Episodes_New", columns.Values);
_subject.CopyData("Episodes", "Episodes_New", columns.Values);
_subject.GetRowCount("Episodes_New").Should().Be(originalEpisodes.Count);
}
}
}

View File

@ -0,0 +1,127 @@
using System.Collections.Generic;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Datastore.Migration.Framework;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using System.Linq;
namespace NzbDrone.Core.Test.Datastore.SQLiteMigrationHelperTests
{
[TestFixture]
public class AlterFixture : DbTest
{
private SqLiteMigrationHelper _subject;
[SetUp]
public void SetUp()
{
_subject = Mocker.Resolve<SqLiteMigrationHelper>();
}
[Test]
public void should_parse_existing_columns()
{
var columns = _subject.GetColumns("Series");
columns.Should().NotBeEmpty();
columns.Values.Should().NotContain(c => string.IsNullOrWhiteSpace(c.Name));
columns.Values.Should().NotContain(c => string.IsNullOrWhiteSpace(c.Schema));
}
[Test]
public void should_create_table_from_column_list()
{
var columns = _subject.GetColumns("Series");
columns.Remove("Title");
_subject.CreateTable("Series_New", columns.Values, new List<SQLiteIndex>());
var newColumns = _subject.GetColumns("Series_New");
newColumns.Values.Should().HaveSameCount(columns.Values);
newColumns.Should().NotContainKey("Title");
}
[Test]
public void should_be_able_to_transfer_empty_tables()
{
var columns = _subject.GetColumns("Series");
var indexes = _subject.GetIndexes("Series");
columns.Remove("Title");
_subject.CreateTable("Series_New", columns.Values, indexes);
_subject.CopyData("Series", "Series_New", columns.Values);
}
[Test]
public void should_transfer_table_with_data()
{
var originalEpisodes = Builder<Episode>.CreateListOfSize(10).BuildListOfNew();
Mocker.Resolve<EpisodeRepository>().InsertMany(originalEpisodes);
var columns = _subject.GetColumns("Episodes");
var indexes = _subject.GetIndexes("Episodes");
columns.Remove("Title");
_subject.CreateTable("Episodes_New", columns.Values, indexes);
_subject.CopyData("Episodes", "Episodes_New", columns.Values);
_subject.GetRowCount("Episodes_New").Should().Be(originalEpisodes.Count);
}
[Test]
public void should_read_existing_indexes()
{
var indexes = _subject.GetIndexes("QualitySizes");
indexes.Should().NotBeEmpty();
indexes.Should().OnlyContain(c => c != null);
indexes.Should().OnlyContain(c => !string.IsNullOrWhiteSpace(c.Column));
indexes.Should().OnlyContain(c => c.Table == "QualitySizes");
indexes.Should().OnlyContain(c => c.Unique);
}
[Test]
public void should_add_indexes_when_creating_new_table()
{
var columns = _subject.GetColumns("QualitySizes");
var indexes = _subject.GetIndexes("QualitySizes");
_subject.CreateTable("QualityB", columns.Values, indexes);
var newIndexes = _subject.GetIndexes("QualityB");
newIndexes.Should().HaveSameCount(indexes);
newIndexes.Select(c=>c.Column).Should().BeEquivalentTo(indexes.Select(c=>c.Column));
}
[Test]
public void should_be_able_to_create_table_with_new_indexes()
{
var columns = _subject.GetColumns("Series");
columns.Remove("Title");
_subject.CreateTable("Series_New", columns.Values, new List<SQLiteIndex>{new SQLiteIndex{Column = "AirTime", Table = "Series_New", Unique = true}});
var newColumns = _subject.GetColumns("Series_New");
var newIndexes = _subject.GetIndexes("Series_New");
newColumns.Values.Should().HaveSameCount(columns.Values);
newIndexes.Should().Contain(i=>i.Column == "AirTime");
}
}
}

View File

@ -0,0 +1,41 @@
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Datastore.Migration.Framework;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.Datastore.SQLiteMigrationHelperTests
{
[TestFixture]
public class DuplicateFixture : DbTest
{
private SqLiteMigrationHelper _subject;
[SetUp]
public void SetUp()
{
_subject = Mocker.Resolve<SqLiteMigrationHelper>();
}
[Test]
public void get_duplicates()
{
var series = Builder<Series>.CreateListOfSize(10)
.Random(3)
.With(c => c.QualityProfileId = 100)
.BuildListOfNew();
Db.InsertMany(series);
var duplicates = _subject.GetDuplicates<int>("series", "QualityProfileId").ToList();
duplicates.Should().HaveCount(1);
duplicates.First().Should().HaveCount(3);
}
}
}

View File

@ -26,14 +26,14 @@ public void Setup()
{
parseResultMulti = new RemoteEpisode
{
Report = new ReportInfo(),
Release = new ReleaseInfo(),
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.SDTV, true) },
Episodes = new List<Episode> { new Episode(), new Episode() }
};
parseResultSingle = new RemoteEpisode
{
Report = new ReportInfo(),
Release = new ReleaseInfo(),
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.SDTV, true) },
Episodes = new List<Episode> { new Episode() }
@ -59,7 +59,7 @@ public void Setup()
public void IsAcceptableSize_true_single_episode_not_first_or_last_30_minute()
{
parseResultSingle.Series = series30minutes;
parseResultSingle.Report.Size = 184572800;
parseResultSingle.Release.Size = 184572800;
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -78,7 +78,7 @@ public void IsAcceptableSize_true_single_episode_not_first_or_last_30_minute()
public void IsAcceptableSize_true_single_episode_not_first_or_last_60_minute()
{
parseResultSingle.Series = series60minutes;
parseResultSingle.Report.Size = 368572800;
parseResultSingle.Release.Size = 368572800;
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -97,7 +97,7 @@ public void IsAcceptableSize_true_single_episode_not_first_or_last_60_minute()
public void IsAcceptableSize_false_single_episode_not_first_or_last_30_minute()
{
parseResultSingle.Series = series30minutes;
parseResultSingle.Report.Size = 1.Gigabytes();
parseResultSingle.Release.Size = 1.Gigabytes();
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -116,7 +116,7 @@ public void IsAcceptableSize_false_single_episode_not_first_or_last_30_minute()
public void IsAcceptableSize_false_single_episode_not_first_or_last_60_minute()
{
parseResultSingle.Series = series60minutes;
parseResultSingle.Report.Size = 1.Gigabytes();
parseResultSingle.Release.Size = 1.Gigabytes();
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -133,7 +133,7 @@ public void IsAcceptableSize_false_single_episode_not_first_or_last_60_minute()
public void IsAcceptableSize_true_multi_episode_not_first_or_last_30_minute()
{
parseResultMulti.Series = series30minutes;
parseResultMulti.Report.Size = 184572800;
parseResultMulti.Release.Size = 184572800;
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -152,7 +152,7 @@ public void IsAcceptableSize_true_multi_episode_not_first_or_last_30_minute()
public void IsAcceptableSize_true_multi_episode_not_first_or_last_60_minute()
{
parseResultMulti.Series = series60minutes;
parseResultMulti.Report.Size = 368572800;
parseResultMulti.Release.Size = 368572800;
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -171,7 +171,7 @@ public void IsAcceptableSize_true_multi_episode_not_first_or_last_60_minute()
public void IsAcceptableSize_false_multi_episode_not_first_or_last_30_minute()
{
parseResultMulti.Series = series30minutes;
parseResultMulti.Report.Size = 1.Gigabytes();
parseResultMulti.Release.Size = 1.Gigabytes();
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -190,7 +190,7 @@ public void IsAcceptableSize_false_multi_episode_not_first_or_last_30_minute()
public void IsAcceptableSize_false_multi_episode_not_first_or_last_60_minute()
{
parseResultMulti.Series = series60minutes;
parseResultMulti.Report.Size = 10.Gigabytes();
parseResultMulti.Release.Size = 10.Gigabytes();
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -209,7 +209,7 @@ public void IsAcceptableSize_false_multi_episode_not_first_or_last_60_minute()
public void IsAcceptableSize_true_single_episode_first_30_minute()
{
parseResultSingle.Series = series30minutes;
parseResultSingle.Report.Size = 184572800;
parseResultSingle.Release.Size = 184572800;
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -228,7 +228,7 @@ public void IsAcceptableSize_true_single_episode_first_30_minute()
public void IsAcceptableSize_true_single_episode_first_60_minute()
{
parseResultSingle.Series = series60minutes;
parseResultSingle.Report.Size = 368572800;
parseResultSingle.Release.Size = 368572800;
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -247,7 +247,7 @@ public void IsAcceptableSize_true_single_episode_first_60_minute()
public void IsAcceptableSize_false_single_episode_first_30_minute()
{
parseResultSingle.Series = series30minutes;
parseResultSingle.Report.Size = 1.Gigabytes();
parseResultSingle.Release.Size = 1.Gigabytes();
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -268,7 +268,7 @@ public void IsAcceptableSize_false_single_episode_first_60_minute()
parseResultSingle.Series = series60minutes;
parseResultSingle.Report.Size = 10.Gigabytes();
parseResultSingle.Release.Size = 10.Gigabytes();
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -289,7 +289,7 @@ public void IsAcceptableSize_true_unlimited_30_minute()
parseResultSingle.Series = series30minutes;
parseResultSingle.Report.Size = 18457280000;
parseResultSingle.Release.Size = 18457280000;
qualityType.MaxSize = 0;
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -311,7 +311,7 @@ public void IsAcceptableSize_true_unlimited_60_minute()
parseResultSingle.Series = series60minutes;
parseResultSingle.Report.Size = 36857280000;
parseResultSingle.Release.Size = 36857280000;
qualityType.MaxSize = 0;
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
@ -334,7 +334,7 @@ public void IsAcceptableSize_should_treat_daily_series_as_single_episode()
parseResultSingle.Series = series60minutes;
parseResultSingle.Series.SeriesType = SeriesTypes.Daily;
parseResultSingle.Report.Size = 300.Megabytes();
parseResultSingle.Release.Size = 300.Megabytes();
qualityType.MaxSize = (int)600.Megabytes();

View File

@ -0,0 +1,48 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.DecisionEngineTests
{
[TestFixture]
public class CutoffSpecificationFixture : CoreTest<QualityUpgradableSpecification>
{
[Test]
public void should_return_true_if_current_episode_is_less_than_cutoff()
{
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.Bluray1080p },
new QualityModel(Quality.DVD, true)).Should().BeTrue();
}
[Test]
public void should_return_false_if_current_episode_is_equal_to_cutoff()
{
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p },
new QualityModel(Quality.HDTV720p, true)).Should().BeFalse();
}
[Test]
public void should_return_false_if_current_episode_is_greater_than_cutoff()
{
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p },
new QualityModel(Quality.Bluray1080p, true)).Should().BeFalse();
}
[Test]
public void should_return_true_when_new_episode_is_proper_but_existing_is_not()
{
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p },
new QualityModel(Quality.HDTV720p, false), new QualityModel(Quality.HDTV720p, true)).Should().BeTrue();
}
[Test]
public void should_return_false_if_cutoff_is_met_and_quality_is_higher()
{
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p },
new QualityModel(Quality.HDTV720p, true), new QualityModel(Quality.Bluray1080p, true)).Should().BeFalse();
}
}
}

View File

@ -4,6 +4,7 @@
using Moq;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
@ -15,7 +16,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[TestFixture]
public class DownloadDecisionMakerFixture : CoreTest<DownloadDecisionMaker>
{
private List<ReportInfo> _reports;
private List<ReleaseInfo> _reports;
private RemoteEpisode _remoteEpisode;
private Mock<IDecisionEngineSpecification> _pass1;
@ -56,10 +57,11 @@ public void Setup()
_fail3.Setup(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null)).Returns(false);
_fail3.Setup(c => c.RejectionReason).Returns("_fail3");
_reports = new List<ReportInfo> { new ReportInfo { Title = "The.Office.S03E115.DVDRip.XviD-OSiTV" } };
_reports = new List<ReleaseInfo> { new ReleaseInfo { Title = "The.Office.S03E115.DVDRip.XviD-OSiTV" } };
_remoteEpisode = new RemoteEpisode { Series = new Series() };
Mocker.GetMock<IParsingService>().Setup(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>()))
Mocker.GetMock<IParsingService>()
.Setup(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()))
.Returns(_remoteEpisode);
}
@ -130,7 +132,7 @@ public void should_not_attempt_to_map_episode_if_not_parsable()
var results = Subject.GetRssDecision(_reports).ToList();
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>()), Times.Never());
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()), Times.Never());
_pass1.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never());
_pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never());
@ -146,7 +148,7 @@ [Test] public void should_not_attempt_to_map_episode_series_title_is_blank()
var results = Subject.GetRssDecision(_reports).ToList();
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>()), Times.Never());
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()), Times.Never());
_pass1.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never());
_pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteEpisode>(), null), Times.Never());
@ -174,19 +176,19 @@ public void broken_report_shouldnt_blowup_the_process()
{
GivenSpecifications(_pass1);
Mocker.GetMock<IParsingService>().Setup(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>()))
Mocker.GetMock<IParsingService>().Setup(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()))
.Throws<TestException>();
_reports = new List<ReportInfo>
_reports = new List<ReleaseInfo>
{
new ReportInfo{Title = "The.Office.S03E115.DVDRip.XviD-OSiTV"},
new ReportInfo{Title = "The.Office.S03E115.DVDRip.XviD-OSiTV"},
new ReportInfo{Title = "The.Office.S03E115.DVDRip.XviD-OSiTV"}
new ReleaseInfo{Title = "The.Office.S03E115.DVDRip.XviD-OSiTV"},
new ReleaseInfo{Title = "The.Office.S03E115.DVDRip.XviD-OSiTV"},
new ReleaseInfo{Title = "The.Office.S03E115.DVDRip.XviD-OSiTV"}
};
Subject.GetRssDecision(_reports);
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>()), Times.Exactly(_reports.Count));
Mocker.GetMock<IParsingService>().Verify(c => c.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()), Times.Exactly(_reports.Count));
ExceptionVerification.ExpectedErrors(3);
}

View File

@ -17,7 +17,7 @@ public void Setup()
{
_parseResult = new RemoteEpisode
{
Report = new ReportInfo
Release = new ReleaseInfo
{
Title = "Dexter.S08E01.EDITED.WEBRip.x264-KYR"
}

View File

@ -1,34 +0,0 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.DecisionEngineTests
{
[TestFixture]
public class QualityUpgradableSpecificationFixture : CoreTest<QualityUpgradableSpecification>
{
[Test]
public void IsUpgradePossible_should_return_true_if_current_episode_is_less_than_cutoff()
{
Subject.IsUpgradable(new QualityProfile { Cutoff = Quality.Bluray1080p },
new QualityModel(Quality.DVD, true)).Should().BeTrue();
}
[Test]
public void IsUpgradePossible_should_return_false_if_current_episode_is_equal_to_cutoff()
{
Subject.IsUpgradable(new QualityProfile { Cutoff = Quality.HDTV720p },
new QualityModel(Quality.HDTV720p, true)).Should().BeFalse();
}
[Test]
public void IsUpgradePossible_should_return_false_if_current_episode_is_greater_than_cutoff()
{
Subject.IsUpgradable(new QualityProfile { Cutoff = Quality.HDTV720p },
new QualityModel(Quality.Bluray1080p, true)).Should().BeFalse();
}
}
}

View File

@ -17,7 +17,6 @@ public class QualityUpgradeSpecificationFixture : CoreTest<QualityUpgradableSpec
new object[] { Quality.SDTV, false, Quality.SDTV, true, Quality.SDTV, true },
new object[] { Quality.WEBDL720p, false, Quality.WEBDL720p, true, Quality.WEBDL720p, true },
new object[] { Quality.SDTV, false, Quality.SDTV, false, Quality.SDTV, false },
new object[] { Quality.SDTV, false, Quality.DVD, true, Quality.SDTV, false },
new object[] { Quality.WEBDL720p, false, Quality.HDTV720p, true, Quality.Bluray720p, false },
new object[] { Quality.WEBDL720p, false, Quality.HDTV720p, true, Quality.WEBDL720p, false },
new object[] { Quality.WEBDL720p, false, Quality.WEBDL720p, false, Quality.WEBDL720p, false },
@ -37,7 +36,7 @@ public void IsUpgradeTest(Quality current, bool currentProper, Quality newQualit
{
GivenAutoDownloadPropers(true);
Subject.IsUpgradable(new QualityProfile() { Cutoff = cutoff }, new QualityModel(current, currentProper), new QualityModel(newQuality, newProper))
Subject.IsUpgradable(new QualityModel(current, currentProper), new QualityModel(newQuality, newProper))
.Should().Be(expected);
}
@ -46,8 +45,7 @@ public void should_return_false_if_proper_and_autoDownloadPropers_is_false()
{
GivenAutoDownloadPropers(false);
Subject.IsUpgradable(new QualityProfile { Cutoff = Quality.Bluray1080p },
new QualityModel(Quality.DVD, true),
Subject.IsUpgradable(new QualityModel(Quality.DVD, true),
new QualityModel(Quality.DVD, false)).Should().BeFalse();
}
}

View File

@ -1,4 +1,5 @@
using FluentAssertions;
using System;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.DecisionEngine.Specifications;
@ -19,9 +20,9 @@ public void Setup()
{
parseResult = new RemoteEpisode
{
Report = new ReportInfo
Release = new ReleaseInfo
{
Age = 100
PublishDate = DateTime.Now.AddDays(-100)
}
};
}

View File

@ -0,0 +1,137 @@
using System;
using System.Collections.Generic;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.DecisionEngine.Specifications.RssSync;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
{
[TestFixture]
public class ProperSpecificationFixture : CoreTest<ProperSpecification>
{
private RemoteEpisode _parseResultMulti;
private RemoteEpisode _parseResultSingle;
private EpisodeFile _firstFile;
private EpisodeFile _secondFile;
[SetUp]
public void Setup()
{
Mocker.Resolve<QualityUpgradableSpecification>();
_firstFile = new EpisodeFile { Quality = new QualityModel(Quality.Bluray1080p, false), DateAdded = DateTime.Now };
_secondFile = new EpisodeFile { Quality = new QualityModel(Quality.Bluray1080p, false), DateAdded = DateTime.Now };
var singleEpisodeList = new List<Episode> { new Episode { EpisodeFile = _firstFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = null } };
var doubleEpisodeList = new List<Episode> { new Episode { EpisodeFile = _firstFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = _secondFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = null } };
var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p })
.Build();
_parseResultMulti = new RemoteEpisode
{
Series = fakeSeries,
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.DVD, true) },
Episodes = doubleEpisodeList
};
_parseResultSingle = new RemoteEpisode
{
Series = fakeSeries,
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.DVD, true) },
Episodes = singleEpisodeList
};
}
private void WithFirstFileUpgradable()
{
_firstFile.Quality = new QualityModel(Quality.SDTV);
}
private void GivenAutoDownloadPropers()
{
Mocker.GetMock<IConfigService>()
.Setup(s => s.AutoDownloadPropers)
.Returns(true);
}
[Test]
public void should_return_false_when_episodeFile_was_added_more_than_7_days_ago()
{
_firstFile.Quality.Quality = Quality.DVD;
_firstFile.DateAdded = DateTime.Today.AddDays(-30);
Subject.IsSatisfiedBy(_parseResultSingle, null).Should().BeFalse();
}
[Test]
public void should_return_false_when_first_episodeFile_was_added_more_than_7_days_ago()
{
_firstFile.Quality.Quality = Quality.DVD;
_secondFile.Quality.Quality = Quality.DVD;
_firstFile.DateAdded = DateTime.Today.AddDays(-30);
Subject.IsSatisfiedBy(_parseResultMulti, null).Should().BeFalse();
}
[Test]
public void should_return_false_when_second_episodeFile_was_added_more_than_7_days_ago()
{
_firstFile.Quality.Quality = Quality.DVD;
_secondFile.Quality.Quality = Quality.DVD;
_secondFile.DateAdded = DateTime.Today.AddDays(-30);
Subject.IsSatisfiedBy(_parseResultMulti, null).Should().BeFalse();
}
[Test]
public void should_return_true_when_episodeFile_was_added_more_than_7_days_ago_but_proper_is_for_better_quality()
{
WithFirstFileUpgradable();
_firstFile.DateAdded = DateTime.Today.AddDays(-30);
Subject.IsSatisfiedBy(_parseResultSingle, null).Should().BeTrue();
}
[Test]
public void should_return_true_when_episodeFile_was_added_more_than_7_days_ago_but_is_for_search()
{
WithFirstFileUpgradable();
_firstFile.DateAdded = DateTime.Today.AddDays(-30);
Subject.IsSatisfiedBy(_parseResultSingle, new SingleEpisodeSearchCriteria()).Should().BeTrue();
}
[Test]
public void should_return_false_when_proper_but_auto_download_propers_is_false()
{
_firstFile.Quality.Quality = Quality.DVD;
_firstFile.DateAdded = DateTime.Today;
Subject.IsSatisfiedBy(_parseResultSingle, null).Should().BeFalse();
}
[Test]
public void should_return_true_when_episodeFile_was_added_today()
{
GivenAutoDownloadPropers();
_firstFile.Quality.Quality = Quality.DVD;
_firstFile.DateAdded = DateTime.Today;
Subject.IsSatisfiedBy(_parseResultSingle, null).Should().BeTrue();
}
}
}

View File

@ -4,7 +4,6 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
@ -124,52 +123,5 @@ public void should_not_be_upgradable_if_qualities_are_the_same()
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, false);
_upgradeDisk.IsSatisfiedBy(_parseResultSingle, null).Should().BeFalse();
}
[Test]
public void should_return_false_when_episodeFile_was_added_more_than_7_days_ago()
{
_firstFile.Quality.Quality = Quality.DVD;
_firstFile.DateAdded = DateTime.Today.AddDays(-30);
_upgradeDisk.IsSatisfiedBy(_parseResultSingle, null).Should().BeFalse();
}
[Test]
public void should_return_false_when_first_episodeFile_was_added_more_than_7_days_ago()
{
_firstFile.Quality.Quality = Quality.DVD;
_secondFile.Quality.Quality = Quality.DVD;
_firstFile.DateAdded = DateTime.Today.AddDays(-30);
_upgradeDisk.IsSatisfiedBy(_parseResultMulti, null).Should().BeFalse();
}
[Test]
public void should_return_false_when_second_episodeFile_was_added_more_than_7_days_ago()
{
_firstFile.Quality.Quality = Quality.DVD;
_secondFile.Quality.Quality = Quality.DVD;
_secondFile.DateAdded = DateTime.Today.AddDays(-30);
_upgradeDisk.IsSatisfiedBy(_parseResultMulti, null).Should().BeFalse();
}
[Test]
public void should_return_true_when_episodeFile_was_added_more_than_7_days_ago_but_proper_is_for_better_quality()
{
WithFirstFileUpgradable();
_firstFile.DateAdded = DateTime.Today.AddDays(-30);
_upgradeDisk.IsSatisfiedBy(_parseResultSingle, null).Should().BeTrue();
}
[Test]
public void should_return_true_when_episodeFile_was_added_more_than_7_days_ago_but_is_for_search()
{
WithFirstFileUpgradable();
_firstFile.DateAdded = DateTime.Today.AddDays(-30);
_upgradeDisk.IsSatisfiedBy(_parseResultSingle, new SingleEpisodeSearchCriteria()).Should().BeTrue();
}
}
}

View File

@ -4,7 +4,7 @@
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Download;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
@ -34,8 +34,8 @@ private RemoteEpisode GetRemoteEpisode(List<Episode> episodes, QualityModel qual
remoteEpisode.Episodes = new List<Episode>();
remoteEpisode.Episodes.AddRange(episodes);
remoteEpisode.Report = new ReportInfo();
remoteEpisode.Report.Age = 0;
remoteEpisode.Release = new ReleaseInfo();
remoteEpisode.Release.PublishDate = DateTime.UtcNow;
return remoteEpisode;
}

View File

@ -1,9 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Download;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
@ -32,9 +33,9 @@ private RemoteEpisode GetRemoteEpisode(List<Episode> episodes, QualityModel qual
remoteEpisode.Episodes = new List<Episode>();
remoteEpisode.Episodes.AddRange(episodes);
remoteEpisode.Report = new ReportInfo();
remoteEpisode.Report.Age = Age;
remoteEpisode.Report.Size = size;
remoteEpisode.Release = new ReleaseInfo();
remoteEpisode.Release.PublishDate = DateTime.Now.AddDays(-Age);
remoteEpisode.Release.Size = size;
return remoteEpisode;
}
@ -110,9 +111,9 @@ public void should_order_by_lowest_number_of_episodes_with_multiple_episodes()
public void should_order_by_smallest_rounded_to_200mb_then_age()
{
var remoteEpisodeSd = GetRemoteEpisode(new List<Episode> { GetEpisode(1) }, new QualityModel(Quality.SDTV), size: 100.Megabytes(), Age: 1);
var remoteEpisodeHdSmallOld = GetRemoteEpisode(new List<Episode> { GetEpisode(1) }, new QualityModel(Quality.HDTV720p), size:1200.Megabytes(), Age:1000);
var remoteEpisodeHdSmallYounge = GetRemoteEpisode(new List<Episode> { GetEpisode(1) }, new QualityModel(Quality.HDTV720p), size:1250.Megabytes(), Age:10);
var remoteEpisodeHdLargeYounge = GetRemoteEpisode(new List<Episode> { GetEpisode(1) }, new QualityModel(Quality.HDTV720p), size:3000.Megabytes(), Age:1);
var remoteEpisodeHdSmallOld = GetRemoteEpisode(new List<Episode> { GetEpisode(1) }, new QualityModel(Quality.HDTV720p), size: 1200.Megabytes(), Age: 1000);
var remoteEpisodeHdSmallYounge = GetRemoteEpisode(new List<Episode> { GetEpisode(1) }, new QualityModel(Quality.HDTV720p), size: 1250.Megabytes(), Age: 10);
var remoteEpisodeHdLargeYounge = GetRemoteEpisode(new List<Episode> { GetEpisode(1) }, new QualityModel(Quality.HDTV720p), size: 3000.Megabytes(), Age: 1);
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisodeSd));

View File

@ -30,9 +30,9 @@ public void Setup()
Mocker.GetMock<IConfigService>().SetupGet(c => c.BlackholeFolder).Returns(_blackHoleFolder);
_remoteEpisode = new RemoteEpisode();
_remoteEpisode.Report = new ReportInfo();
_remoteEpisode.Report.Title = _title;
_remoteEpisode.Report.NzbUrl = _nzbUrl;
_remoteEpisode.Release = new ReleaseInfo();
_remoteEpisode.Release.Title = _title;
_remoteEpisode.Release.DownloadUrl = _nzbUrl;
}
private void WithExistingFile()
@ -58,7 +58,7 @@ public void should_replace_illegal_characters_in_title()
{
var illegalTitle = "Saturday Night Live - S38E08 - Jeremy Renner/Maroon 5 [SDTV]";
var expectedFilename = Path.Combine(_blackHoleFolder, "Saturday Night Live - S38E08 - Jeremy Renner+Maroon 5 [SDTV].nzb");
_remoteEpisode.Report.Title = illegalTitle;
_remoteEpisode.Release.Title = illegalTitle;
Subject.DownloadNzb(_remoteEpisode);

Some files were not shown because too many files have changed in this diff Show More