diff --git a/NzbDrone.Api/NancyBootstrapper.cs b/NzbDrone.Api/NancyBootstrapper.cs index e51e211a5..7bc4649f9 100644 --- a/NzbDrone.Api/NancyBootstrapper.cs +++ b/NzbDrone.Api/NancyBootstrapper.cs @@ -13,12 +13,12 @@ using TinyIoC; namespace NzbDrone.Api { - public class TinyNancyBootstrapper : TinyIoCNancyBootstrapper + public class NancyBootstrapper : TinyIoCNancyBootstrapper { private readonly TinyIoCContainer _tinyIoCContainer; private readonly Logger _logger; - public TinyNancyBootstrapper(TinyIoCContainer tinyIoCContainer) + public NancyBootstrapper(TinyIoCContainer tinyIoCContainer) { _tinyIoCContainer = tinyIoCContainer; _logger = LogManager.GetCurrentClassLogger(); @@ -70,5 +70,10 @@ namespace NzbDrone.Api var processors = ApplicationContainer.Resolve(); Conventions.StaticContentsConventions.Add(processors.ProcessStaticResourceRequest); } + + public void Shutdown() + { + ApplicationContainer.Resolve().Publish(new ApplicationShutdownRequested()); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Jobs/JobController.cs b/NzbDrone.Core/Jobs/JobController.cs index 6f0398ae2..4a4360447 100644 --- a/NzbDrone.Core/Jobs/JobController.cs +++ b/NzbDrone.Core/Jobs/JobController.cs @@ -6,6 +6,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using NLog; +using NzbDrone.Common.Eventing; +using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Providers; @@ -20,7 +22,7 @@ namespace NzbDrone.Core.Jobs bool Enqueue(string jobTypeString); } - public class JobController : IJobController + public class JobController : IJobController, IHandle { private readonly NotificationProvider _notificationProvider; private readonly IEnumerable _jobs; @@ -177,5 +179,10 @@ namespace NzbDrone.Core.Jobs _jobRepository.Update(jobDefinition); } } + + public void Handle(ApplicationShutdownRequested message) + { + _cancellationTokenSource.Cancel(); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Jobs/JobTimer.cs b/NzbDrone.Core/Jobs/JobTimer.cs index 6300cbb3a..c68e997e2 100644 --- a/NzbDrone.Core/Jobs/JobTimer.cs +++ b/NzbDrone.Core/Jobs/JobTimer.cs @@ -4,7 +4,9 @@ using NzbDrone.Core.Lifecycle; namespace NzbDrone.Core.Jobs { - public class JobTimer : IHandle + public class JobTimer : + IHandle, + IHandle { private readonly IJobController _jobController; private readonly Timer _timer; @@ -22,5 +24,10 @@ namespace NzbDrone.Core.Jobs _timer.Elapsed += (o, args) => _jobController.EnqueueScheduled(); _timer.Start(); } + + public void Handle(ApplicationShutdownRequested message) + { + _timer.Stop(); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Lifecycle/ApplicationShutdownRequested.cs b/NzbDrone.Core/Lifecycle/ApplicationShutdownRequested.cs new file mode 100644 index 000000000..e5610058e --- /dev/null +++ b/NzbDrone.Core/Lifecycle/ApplicationShutdownRequested.cs @@ -0,0 +1,9 @@ +using NzbDrone.Common.Eventing; + +namespace NzbDrone.Core.Lifecycle +{ + public class ApplicationShutdownRequested : IEvent + { + + } +} \ No newline at end of file diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index cb207b25b..1bb52baf0 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -1,4 +1,4 @@ - + Debug @@ -235,6 +235,7 @@ + diff --git a/NzbDrone.Integration.Test/Client/ClientBase.cs b/NzbDrone.Integration.Test/Client/ClientBase.cs new file mode 100644 index 000000000..ae7d15e89 --- /dev/null +++ b/NzbDrone.Integration.Test/Client/ClientBase.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Net; +using FluentAssertions; +using NLog; +using RestSharp; + +namespace NzbDrone.Integration.Test.Client +{ + public abstract class ClientBase where TResource : new() + { + private readonly IRestClient _restClient; + private readonly string _resource; + + private readonly Logger _logger; + + protected ClientBase(IRestClient restClient, string resource) + { + _restClient = restClient; + _resource = resource; + _logger = LogManager.GetLogger("REST"); + } + + public List GetAll() + { + var request = BuildRequest(); + return Get>(request); + } + + public TResource Post(TResource body) + { + var request = BuildRequest(); + request.AddBody(body); + return Post(request); + } + + protected RestRequest BuildRequest(string command = "") + { + return new RestRequest(_resource + "/" + command.Trim('/')) + { + RequestFormat = DataFormat.Json + }; + } + + protected T Get(IRestRequest request, HttpStatusCode statusCode = HttpStatusCode.OK) where T : new() + { + request.Method = Method.GET; + return Execute(request, statusCode); + } + + public T Post(IRestRequest request, HttpStatusCode statusCode = HttpStatusCode.Created) where T : new() + { + request.Method = Method.POST; + return Execute(request, statusCode); + } + + private T Execute(IRestRequest request, HttpStatusCode statusCode) where T : new() + { + _logger.Info("{0}: {1}", request.Method, _restClient.BuildUri(request)); + + var response = _restClient.Execute(request); + + _logger.Info("Response: {0}", response.Content); + + if (response.ErrorException != null) + { + throw response.ErrorException; + } + + response.ErrorMessage.Should().BeBlank(); + + + response.StatusCode.Should().Be(statusCode); + + return response.Data; + } + + } +} \ No newline at end of file diff --git a/NzbDrone.Integration.Test/Client/SeriesClient.cs b/NzbDrone.Integration.Test/Client/SeriesClient.cs new file mode 100644 index 000000000..68de54608 --- /dev/null +++ b/NzbDrone.Integration.Test/Client/SeriesClient.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using NzbDrone.Api.Series; +using RestSharp; + +namespace NzbDrone.Integration.Test.Client +{ + public class SeriesClient : ClientBase + { + public SeriesClient(IRestClient restClient) + : base(restClient, "series") + { + } + + public List Lookup(string term) + { + var request = BuildRequest("lookup?term={term}"); + request.AddUrlSegment("term", term); + return Get>(request); + } + + } +} \ No newline at end of file diff --git a/NzbDrone.Smoke.Test/NzbDrone.Smoke.Test.csproj b/NzbDrone.Integration.Test/NzbDrone.Integration.Test.csproj similarity index 94% rename from NzbDrone.Smoke.Test/NzbDrone.Smoke.Test.csproj rename to NzbDrone.Integration.Test/NzbDrone.Integration.Test.csproj index ff2fc301a..41cba8aa5 100644 --- a/NzbDrone.Smoke.Test/NzbDrone.Smoke.Test.csproj +++ b/NzbDrone.Integration.Test/NzbDrone.Integration.Test.csproj @@ -7,8 +7,8 @@ {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB} Library Properties - NzbDrone.Smoke.Test - NzbDrone.Smoke.Test + NzbDrone.Integration.Test + NzbDrone.Integration.Test v4.0 512 ..\ @@ -66,9 +66,11 @@ + + - + diff --git a/NzbDrone.Smoke.Test/Properties/AssemblyInfo.cs b/NzbDrone.Integration.Test/Properties/AssemblyInfo.cs similarity index 100% rename from NzbDrone.Smoke.Test/Properties/AssemblyInfo.cs rename to NzbDrone.Integration.Test/Properties/AssemblyInfo.cs diff --git a/NzbDrone.Integration.Test/SeriesTest.cs b/NzbDrone.Integration.Test/SeriesTest.cs new file mode 100644 index 000000000..5e37be243 --- /dev/null +++ b/NzbDrone.Integration.Test/SeriesTest.cs @@ -0,0 +1,33 @@ +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Api.Series; + +namespace NzbDrone.Integration.Test +{ + [TestFixture] + public class SeriesTest : SmokeTestBase + { + [Test] + public void should_have_no_series_on_start_application() + { + Series.GetAll().Should().BeEmpty(); + } + + [Test] + public void series_lookup_on_trakt() + { + var series = Series.Lookup("archer"); + + series.Should().NotBeEmpty(); + series.Should().Contain(c => c.Title == "Archer (2009)"); + } + + [Test] + [Ignore] + public void add_series_without_required_fields_should_return_400() + { + Series.Post(new SeriesResource()); + } + + } +} \ No newline at end of file diff --git a/NzbDrone.Integration.Test/SmokeTestBase.cs b/NzbDrone.Integration.Test/SmokeTestBase.cs new file mode 100644 index 000000000..6486015d6 --- /dev/null +++ b/NzbDrone.Integration.Test/SmokeTestBase.cs @@ -0,0 +1,96 @@ +using System; +using System.IO; +using NLog; +using NLog.Config; +using NLog.Targets; +using NUnit.Framework; +using Nancy.Hosting.Self; +using NzbDrone.Api; +using NzbDrone.Common; +using NzbDrone.Core.Datastore; +using NzbDrone.Integration.Test.Client; +using RestSharp; +using TinyIoC; + +namespace NzbDrone.Integration.Test +{ + [TestFixture] + public abstract class SmokeTestBase + { + private NancyBootstrapper _bootstrapper; + private NancyHost _host; + protected RestClient RestClient { get; private set; } + + private static readonly Logger Logger = LogManager.GetLogger("TEST"); + + protected TinyIoCContainer Container { get; private set; } + + + protected SeriesClient Series; + + static SmokeTestBase() + { + if (LogManager.Configuration == null || LogManager.Configuration is XmlLoggingConfiguration) + { + LogManager.Configuration = new LoggingConfiguration(); + var consoleTarget = new ConsoleTarget { Layout = "${logger} - ${message} ${exception}" }; + LogManager.Configuration.AddTarget(consoleTarget.GetType().Name, consoleTarget); + LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, consoleTarget)); + } + + + LogManager.ReconfigExistingLoggers(); + } + + private void InitDatabase() + { + Logger.Info("Registering Database..."); + + //TODO: move this to factory + var environmentProvider = new EnvironmentProvider(); + var appDataPath = environmentProvider.GetAppDataPath(); + + if (!Directory.Exists(appDataPath)) + { + Directory.CreateDirectory(appDataPath); + } + + var dbPath = Path.Combine(environmentProvider.WorkingDirectory, DateTime.Now.Ticks + ".db"); + + + Logger.Info("Working Folder: {0}", environmentProvider.WorkingDirectory); + Logger.Info("Data Folder: {0}", environmentProvider.GetAppDataPath()); + Logger.Info("DB Na: {0}", dbPath); + + + Container.Register((c, p) => c.Resolve().Create(dbPath)); + } + + [SetUp] + public void SmokeTestSetup() + { + Container = ContainerBuilder.BuildNzbDroneContainer(); + + InitDatabase(); + + _bootstrapper = new NancyBootstrapper(Container); + + const string url = "http://localhost:1313"; + + _host = new NancyHost(new Uri(url), _bootstrapper); + + RestClient = new RestClient(url + "/api/"); + Series = new SeriesClient(RestClient); + + _host.Start(); + } + + [TearDown] + public void SmokeTestTearDown() + { + _host.Stop(); + + _bootstrapper.Shutdown(); + } + } +} diff --git a/NzbDrone.Smoke.Test/packages.config b/NzbDrone.Integration.Test/packages.config similarity index 100% rename from NzbDrone.Smoke.Test/packages.config rename to NzbDrone.Integration.Test/packages.config diff --git a/NzbDrone.Smoke.Test/SmokeTest.cs b/NzbDrone.Smoke.Test/SmokeTest.cs deleted file mode 100644 index 12ae34695..000000000 --- a/NzbDrone.Smoke.Test/SmokeTest.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using NUnit.Framework; -using NzbDrone.Api.Series; -using RestSharp; - -namespace NzbDrone.Smoke.Test -{ - [TestFixture] - public class SmokeTest : SmokeTestBase - { - [Test] - public void start_application() - { - Get>(new RestRequest("series")); - } - - [Test] - [Ignore] - public void add_series_without_required_fields_should_return_400() - { - var addSeriesRequest = new RestRequest("series") { RequestFormat = DataFormat.Json }; - addSeriesRequest.AddBody(new SeriesResource()); - Post(addSeriesRequest); - } - - } -} \ No newline at end of file diff --git a/NzbDrone.Smoke.Test/SmokeTestBase.cs b/NzbDrone.Smoke.Test/SmokeTestBase.cs deleted file mode 100644 index 6c8b5ca4d..000000000 --- a/NzbDrone.Smoke.Test/SmokeTestBase.cs +++ /dev/null @@ -1,124 +0,0 @@ -using System; -using System.IO; -using System.Net; -using FluentAssertions; -using NLog; -using NLog.Config; -using NLog.Targets; -using NUnit.Framework; -using Nancy.Hosting.Self; -using NzbDrone.Api; -using NzbDrone.Common; -using RestSharp; -using TinyIoC; - -namespace NzbDrone.Smoke.Test -{ - [TestFixture] - public abstract class SmokeTestBase - { - private TinyNancyBootstrapper _bootstrapper; - private NancyHost _host; - protected RestClient RestClient { get; private set; } - - private static readonly Logger RestLogger = LogManager.GetLogger("REST: "); - private static readonly Logger Logger = LogManager.GetLogger("TEST: "); - private EnvironmentProvider _environmentProvider; - - protected TinyIoCContainer Container { get; private set; } - - - static SmokeTestBase() - { - if (LogManager.Configuration == null || LogManager.Configuration is XmlLoggingConfiguration) - { - LogManager.Configuration = new LoggingConfiguration(); - var consoleTarget = new ConsoleTarget { Layout = "${message} ${exception}" }; - LogManager.Configuration.AddTarget(consoleTarget.GetType().Name, consoleTarget); - LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, consoleTarget)); - } - - - LogManager.ReconfigExistingLoggers(); - } - - - [SetUp] - public void SmokeTestSetup() - { - - _environmentProvider = new EnvironmentProvider(); - - if (Directory.Exists(_environmentProvider.GetAppDataPath())) - { - Directory.Delete(_environmentProvider.GetAppDataPath(), true); - } - - Logger.Info("Working Folder: {0}", _environmentProvider.WorkingDirectory); - Logger.Info("Data Folder: {0}", _environmentProvider.GetAppDataPath()); - Logger.Info("DB Path: {0}", _environmentProvider.GetNzbDroneDatabase()); - - - Container = ContainerBuilder.BuildNzbDroneContainer(); - _bootstrapper = new TinyNancyBootstrapper(Container); - - const string url = "http://localhost:1313"; - - _host = new NancyHost(new Uri(url), _bootstrapper); - - RestClient = new RestClient(url + "/api/"); - - - _host.Start(); - } - - [TearDown] - public void SmokeTestTearDown() - { - _host.Stop(); - } - - - protected T Get(IRestRequest request, HttpStatusCode statusCode = HttpStatusCode.OK) where T : class,new() - { - RestLogger.Info("GET: {0}", RestClient.BuildUri(request)); - - var response = RestClient.Get(request); - - RestLogger.Info("Response: {0}", response.Content); - - if (response.ErrorException != null) - { - throw response.ErrorException; - } - - response.ErrorMessage.Should().BeBlank(); - - response.StatusCode.Should().Be(statusCode); - - return response.Data; - } - - protected T Post(IRestRequest request, HttpStatusCode statusCode = HttpStatusCode.Created) where T : class,new() - { - RestLogger.Info("POST: {0}", RestClient.BuildUri(request)); - - var response = RestClient.Post(request); - - RestLogger.Info("Response: {0}", response.Content); - - if (response.ErrorException != null) - { - throw response.ErrorException; - } - - response.ErrorMessage.Should().BeBlank(); - - - response.StatusCode.Should().Be(statusCode); - - return response.Data; - } - - } -} diff --git a/NzbDrone.sln b/NzbDrone.sln index 10390a73c..461e27c2f 100644 --- a/NzbDrone.sln +++ b/NzbDrone.sln @@ -48,7 +48,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marr.Data", "Marr.Data\Marr EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Libraries.Test", "NzbDrone.Libraries.Test\NzbDrone.Libraries.Test.csproj", "{CBF6B8B0-A015-413A-8C86-01238BB45770}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Smoke.Test", "NzbDrone.Smoke.Test\NzbDrone.Smoke.Test.csproj", "{8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Integration.Test", "NzbDrone.Integration.Test\NzbDrone.Integration.Test.csproj", "{8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/NzbDrone/ContainerBuilder.cs b/NzbDrone/ContainerBuilder.cs index 002366a0b..2fa521394 100644 --- a/NzbDrone/ContainerBuilder.cs +++ b/NzbDrone/ContainerBuilder.cs @@ -41,7 +41,7 @@ namespace NzbDrone container.AutoRegisterImplementations(); container.Register().AsSingleton(); - container.Register().AsSingleton(); + container.Register().AsSingleton(); container.Register().AsSingleton(); container.Register().AsSingleton();