{
- updateMechanism === 'builtIn' || updateMechanism === 'script' ?
-
- Install Latest
- :
+ !isDocker &&
+
+ Install Latest
+
+ }
-
-
-
-
- {externalUpdaterMessages[updateMechanism] || externalUpdaterMessages.external}
-
-
+ {
+ isDocker &&
+
+ An update is available. Please update your Docker image and re-create the container.
+
}
{
@@ -209,6 +198,7 @@ Updates.propTypes = {
generalSettingsError: PropTypes.object,
items: PropTypes.array.isRequired,
isInstallingUpdate: PropTypes.bool.isRequired,
+ isDocker: PropTypes.bool.isRequired,
updateMechanism: PropTypes.string,
shortDateFormat: PropTypes.string.isRequired,
onInstallLatestPress: PropTypes.func.isRequired
diff --git a/frontend/src/System/Updates/UpdatesConnector.js b/frontend/src/System/Updates/UpdatesConnector.js
index 8836bbb94..4003eed54 100644
--- a/frontend/src/System/Updates/UpdatesConnector.js
+++ b/frontend/src/System/Updates/UpdatesConnector.js
@@ -7,6 +7,7 @@ import { fetchUpdates } from 'Store/Actions/systemActions';
import { executeCommand } from 'Store/Actions/commandActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
+import createSystemStatusSelector from 'Store/Selectors/createSystemStatusSelector';
import * as commandNames from 'Commands/commandNames';
import Updates from './Updates';
@@ -16,12 +17,14 @@ function createMapStateToProps() {
(state) => state.system.updates,
(state) => state.settings.general,
createUISettingsSelector(),
+ createSystemStatusSelector(),
createCommandExecutingSelector(commandNames.APPLICATION_UPDATE),
(
currentVersion,
updates,
generalSettings,
uiSettings,
+ systemStatus,
isInstallingUpdate
) => {
const {
@@ -40,6 +43,7 @@ function createMapStateToProps() {
generalSettingsError: generalSettings.error,
items,
isInstallingUpdate,
+ isDocker: systemStatus.isDocker,
updateMechanism: generalSettings.item.updateMechanism,
shortDateFormat: uiSettings.shortDateFormat
};
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index c437d8012..87469695d 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -20,8 +20,10 @@
+ Release
- $(RadarrRootDir)_temp\obj\$(Configuration)\$(MSBuildProjectName)\
+ $(RadarrRootDir)_temp\obj\$(MSBuildProjectName)\
+ $(RadarrRootDir)_temp\obj\$(MSBuildProjectName)\$(Configuration)\
$(RadarrRootDir)_temp\bin\$(Configuration)\$(MSBuildProjectName)\
@@ -30,6 +32,7 @@
$(RadarrRootDir)_output\Radarr.Update\
+ $([MSBuild]::MakeRelative('$(MSBuildProjectDirectory)', '$(BaseIntermediateOutputPath)'))
$([MSBuild]::MakeRelative('$(MSBuildProjectDirectory)', '$(IntermediateOutputPath)'))
$([MSBuild]::MakeRelative('$(MSBuildProjectDirectory)', '$(OutputPath)'))
diff --git a/src/ExternalModules/CurlSharp b/src/ExternalModules/CurlSharp
deleted file mode 160000
index cfdbbbd9c..000000000
--- a/src/ExternalModules/CurlSharp
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit cfdbbbd9c6b9612c2756245049a8234ce87dc576
diff --git a/src/NzbDrone.Api/Logs/LogFileModuleBase.cs b/src/NzbDrone.Api/Logs/LogFileModuleBase.cs
index e719bafdd..8e78848c5 100644
--- a/src/NzbDrone.Api/Logs/LogFileModuleBase.cs
+++ b/src/NzbDrone.Api/Logs/LogFileModuleBase.cs
@@ -1,9 +1,10 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using NzbDrone.Common.Disk;
using Nancy;
using Nancy.Responses;
+using NLog;
+using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
using Radarr.Http;
@@ -54,6 +55,8 @@ private List GetLogFilesResponse()
private Response GetLogFileResponse(string filename)
{
+ LogManager.Flush();
+
var filePath = GetLogFilePath(filename);
if (!_diskProvider.FileExists(filePath))
diff --git a/src/NzbDrone.Automation.Test/AutomationTest.cs b/src/NzbDrone.Automation.Test/AutomationTest.cs
index 01c307b67..c3de80202 100644
--- a/src/NzbDrone.Automation.Test/AutomationTest.cs
+++ b/src/NzbDrone.Automation.Test/AutomationTest.cs
@@ -34,7 +34,9 @@ public AutomationTest()
[OneTimeSetUp]
public void SmokeTestSetup()
{
- driver = new FirefoxDriver();
+ var options = new FirefoxOptions();
+ options.AddArguments("--headless");
+ driver = new FirefoxDriver(options);
_runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger());
_runner.KillAll();
@@ -45,7 +47,7 @@ public void SmokeTestSetup()
var page = new PageBase(driver);
page.WaitForNoSpinner();
- driver.ExecuteScript("window.NzbDrone.NameViews = true;");
+ driver.ExecuteScript("window.Radarr.NameViews = true;");
GetPageErrors().Should().BeEmpty();
}
diff --git a/src/NzbDrone.Automation.Test/MainPagesTest.cs b/src/NzbDrone.Automation.Test/MainPagesTest.cs
index bbf89690a..7737751ca 100644
--- a/src/NzbDrone.Automation.Test/MainPagesTest.cs
+++ b/src/NzbDrone.Automation.Test/MainPagesTest.cs
@@ -17,11 +17,11 @@ public void Setup()
}
[Test]
- public void series_page()
+ public void movie_page()
{
- page.SeriesNavIcon.Click();
+ page.MovieNavIcon.Click();
page.WaitForNoSpinner();
- page.FindByClass("iv-series-index-seriesindexlayout").Should().NotBeNull();
+ page.Find(By.CssSelector("div[class*='MovieIndex']")).Should().NotBeNull();
}
[Test]
@@ -30,7 +30,7 @@ public void calendar_page()
page.CalendarNavIcon.Click();
page.WaitForNoSpinner();
- page.FindByClass("iv-calendar-calendarlayout").Should().NotBeNull();
+ page.Find(By.CssSelector("div[class*='CalendarPage']")).Should().NotBeNull();
}
[Test]
@@ -39,16 +39,9 @@ public void activity_page()
page.ActivityNavIcon.Click();
page.WaitForNoSpinner();
- page.FindByClass("iv-activity-activitylayout").Should().NotBeNull();
- }
-
- [Test]
- public void wanted_page()
- {
- page.WantedNavIcon.Click();
- page.WaitForNoSpinner();
-
- page.FindByClass("iv-wanted-missing-missinglayout").Should().NotBeNull();
+ page.Find(By.LinkText("Queue")).Should().NotBeNull();
+ page.Find(By.LinkText("History")).Should().NotBeNull();
+ page.Find(By.LinkText("Blacklist")).Should().NotBeNull();
}
[Test]
@@ -57,20 +50,20 @@ public void system_page()
page.SystemNavIcon.Click();
page.WaitForNoSpinner();
- page.FindByClass("iv-system-systemlayout").Should().NotBeNull();
+ page.Find(By.CssSelector("div[class*='Health']")).Should().NotBeNull();
}
[Test]
- public void add_series_page()
+ public void add_movie_page()
{
- page.SeriesNavIcon.Click();
+ page.MovieNavIcon.Click();
page.WaitForNoSpinner();
- page.Find(By.LinkText("Add Series")).Click();
+ page.Find(By.LinkText("Add New")).Click();
page.WaitForNoSpinner();
- page.FindByClass("iv-addseries-addserieslayout").Should().NotBeNull();
+ page.Find(By.CssSelector("input[class*='AddNewMovie/searchInput']")).Should().NotBeNull();
}
}
}
\ No newline at end of file
diff --git a/src/NzbDrone.Automation.Test/PageModel/PageBase.cs b/src/NzbDrone.Automation.Test/PageModel/PageBase.cs
index f835c39a6..c0db1ab50 100644
--- a/src/NzbDrone.Automation.Test/PageModel/PageBase.cs
+++ b/src/NzbDrone.Automation.Test/PageModel/PageBase.cs
@@ -47,16 +47,14 @@ public void WaitForNoSpinner(int timeout = 30)
});
}
- public IWebElement SeriesNavIcon => FindByClass("x-series-nav");
+ public IWebElement MovieNavIcon => Find(By.LinkText("Movies"));
- public IWebElement CalendarNavIcon => FindByClass("x-calendar-nav");
+ public IWebElement CalendarNavIcon => Find(By.LinkText("Calendar"));
- public IWebElement ActivityNavIcon => FindByClass("x-activity-nav");
+ public IWebElement ActivityNavIcon => Find(By.LinkText("Activity"));
- public IWebElement WantedNavIcon => FindByClass("x-wanted-nav");
+ public IWebElement SettingNavIcon => Find(By.LinkText("Settings"));
- public IWebElement SettingNavIcon => FindByClass("x-settings-nav");
-
- public IWebElement SystemNavIcon => FindByClass("x-system-nav");
+ public IWebElement SystemNavIcon => Find(By.PartialLinkText("System"));
}
}
\ No newline at end of file
diff --git a/src/NzbDrone.Automation.Test/Radarr.Automation.Test.csproj b/src/NzbDrone.Automation.Test/Radarr.Automation.Test.csproj
index 08ec8b7e6..b75dddef3 100644
--- a/src/NzbDrone.Automation.Test/Radarr.Automation.Test.csproj
+++ b/src/NzbDrone.Automation.Test/Radarr.Automation.Test.csproj
@@ -4,6 +4,7 @@
x86
+
diff --git a/src/NzbDrone.Common.Test/DiskTests/DiskProviderFixtureBase.cs b/src/NzbDrone.Common.Test/DiskTests/DiskProviderFixtureBase.cs
index 61ad8f8e6..f02b07d7a 100644
--- a/src/NzbDrone.Common.Test/DiskTests/DiskProviderFixtureBase.cs
+++ b/src/NzbDrone.Common.Test/DiskTests/DiskProviderFixtureBase.cs
@@ -248,12 +248,14 @@ public void should_be_able_to_rename_open_hardlinks_with_fileshare_delete()
}
[Test]
+ [Ignore("No longer behaving this way in a Windows 10 Feature Update")]
public void should_not_be_able_to_rename_open_hardlinks_with_fileshare_none()
{
Assert.Throws(() => DoHardLinkRename(FileShare.None));
}
[Test]
+ [Ignore("No longer behaving this way in a Windows 10 Feature Update")]
public void should_not_be_able_to_rename_open_hardlinks_with_fileshare_write()
{
Assert.Throws(() => DoHardLinkRename(FileShare.Read));
diff --git a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs
index b072ff395..fef4ec4b6 100644
--- a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs
+++ b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs
@@ -22,7 +22,6 @@ namespace NzbDrone.Common.Test.Http
{
[IntegrationTest]
[TestFixture(typeof(ManagedHttpDispatcher))]
- [TestFixture(typeof(CurlHttpDispatcher))]
public class HttpClientFixture : TestBase where TDispatcher : IHttpDispatcher
{
private string[] _httpBinHosts;
diff --git a/src/NzbDrone.Common.Test/ProcessProviderTests.cs b/src/NzbDrone.Common.Test/ProcessProviderTests.cs
index 3bbe5a7d7..b4ea33b7c 100644
--- a/src/NzbDrone.Common.Test/ProcessProviderTests.cs
+++ b/src/NzbDrone.Common.Test/ProcessProviderTests.cs
@@ -9,22 +9,21 @@
using NzbDrone.Common.Processes;
using NzbDrone.Test.Common;
using NzbDrone.Test.Dummy;
-using System.Reflection;
namespace NzbDrone.Common.Test
{
[TestFixture]
- public class ProcessProviderTests : TestBase
+ public class ProcessProviderFixture : TestBase
{
[SetUp]
public void Setup()
{
Process.GetProcessesByName(DummyApp.DUMMY_PROCCESS_NAME).ToList().ForEach(c =>
- {
- c.Kill();
- c.WaitForExit();
- });
+ {
+ c.Kill();
+ c.WaitForExit();
+ });
Process.GetProcessesByName(DummyApp.DUMMY_PROCCESS_NAME).Should().BeEmpty();
}
@@ -42,7 +41,7 @@ public void TearDown()
{
TestLogger.Warn(ex, "{0} when killing process", ex.Message);
}
-
+
});
}
@@ -65,18 +64,9 @@ public void GetProcessById_should_return_null_for_invalid_process(int processId)
}
[Test]
- [Ignore("Shit appveyor")]
public void Should_be_able_to_start_process()
- {
- string codeBase = Assembly.GetExecutingAssembly().CodeBase;
- UriBuilder uri = new UriBuilder(codeBase);
- string path = Uri.UnescapeDataString(uri.Path);
- var rPath = Path.GetDirectoryName(path);
-
- var root = Directory.GetParent(rPath).Parent.Parent.Parent;
- var DummyAppDir = Path.Combine(root.FullName, "NzbDrone.Test.Dummy", "bin", "Release");
-
- var process = Subject.Start(Path.Combine(DummyAppDir, DummyApp.DUMMY_PROCCESS_NAME + ".exe"));
+ {
+ var process = StartDummyProcess();
Subject.Exists(DummyApp.DUMMY_PROCCESS_NAME).Should()
.BeTrue("excepted one dummy process to be already running");
@@ -88,6 +78,7 @@ public void Should_be_able_to_start_process()
}
[Test]
+ [Explicit]
public void Should_be_able_to_start_powershell()
{
WindowsOnly();
@@ -137,7 +128,6 @@ public void Should_be_able_to_start_python()
[Test]
- [Ignore("Shit appveyor")]
public void kill_all_should_kill_all_process_with_name()
{
var dummy1 = StartDummyProcess();
@@ -151,7 +141,8 @@ public void kill_all_should_kill_all_process_with_name()
private Process StartDummyProcess()
{
- return Subject.Start(DummyApp.DUMMY_PROCCESS_NAME + ".exe");
+ var path = Path.Combine(TestContext.CurrentContext.TestDirectory, DummyApp.DUMMY_PROCCESS_NAME + ".exe");
+ return Subject.Start(path);
}
[Test]
@@ -161,4 +152,4 @@ public void ToString_on_new_processInfo()
ExceptionVerification.MarkInconclusive(typeof(Win32Exception));
}
}
-}
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Common.Test/Radarr.Common.Test.csproj b/src/NzbDrone.Common.Test/Radarr.Common.Test.csproj
index 5c5418813..33335d8ae 100644
--- a/src/NzbDrone.Common.Test/Radarr.Common.Test.csproj
+++ b/src/NzbDrone.Common.Test/Radarr.Common.Test.csproj
@@ -11,9 +11,4 @@
-
-
- PreserveNewest
-
-
\ No newline at end of file
diff --git a/src/NzbDrone.Common.Test/ServiceProviderTests.cs b/src/NzbDrone.Common.Test/ServiceProviderTests.cs
index b9cf4e220..893cdf567 100644
--- a/src/NzbDrone.Common.Test/ServiceProviderTests.cs
+++ b/src/NzbDrone.Common.Test/ServiceProviderTests.cs
@@ -1,4 +1,5 @@
using System;
+using System.Security.Principal;
using System.ServiceProcess;
using FluentAssertions;
using NUnit.Framework;
@@ -61,6 +62,10 @@ public void Exists_should_not_find_random_service()
[Test]
public void Service_should_be_installed_and_then_uninstalled()
{
+ if (!IsAnAdministrator())
+ {
+ Assert.Inconclusive("Can't run test without Administrator rights");
+ }
Subject.ServiceExist(TEMP_SERVICE_NAME).Should().BeFalse("Service already installed");
Subject.Install(TEMP_SERVICE_NAME);
@@ -100,9 +105,13 @@ public void Should_be_able_to_start_and_stop_service()
}
[Test]
- [Ignore("Shit appveyor")]
- public void should_throw_if_starting_a_running_serivce()
+ public void should_throw_if_starting_a_running_service()
{
+ if (!IsAnAdministrator())
+ {
+ Assert.Inconclusive("Can't run test without Administrator rights");
+ }
+
Subject.GetService(ALWAYS_INSTALLED_SERVICE).Status
.Should().NotBe(ServiceControllerStatus.Running);
@@ -128,5 +137,10 @@ public void Should_log_warn_if_on_stop_if_service_is_already_stopped()
ExceptionVerification.ExpectedWarns(1);
}
+ private static bool IsAnAdministrator()
+ {
+ var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
+ return principal.IsInRole(WindowsBuiltInRole.Administrator);
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Common/CurlSharp.dll.config b/src/NzbDrone.Common/CurlSharp.dll.config
deleted file mode 100644
index eadeb9ad7..000000000
--- a/src/NzbDrone.Common/CurlSharp.dll.config
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/NzbDrone.Common/EnvironmentInfo/BuildInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/BuildInfo.cs
index 6a25d5b20..091abf0e9 100644
--- a/src/NzbDrone.Common/EnvironmentInfo/BuildInfo.cs
+++ b/src/NzbDrone.Common/EnvironmentInfo/BuildInfo.cs
@@ -27,6 +27,8 @@ static BuildInfo()
Release = $"{Version}-{Branch}";
}
+ public static string AppName { get; } = "Radarr";
+
public static Version Version { get; }
public static String Branch { get; }
public static string Release { get; }
diff --git a/src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs
index 80993e8a6..36d760b2c 100644
--- a/src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs
+++ b/src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs
@@ -15,6 +15,9 @@ public class OsInfo : IOsInfo
public static bool IsOsx => Os == Os.Osx;
public static bool IsWindows => Os == Os.Windows;
+ // this needs to not be static so we can mock it
+ public bool IsDocker { get; }
+
public string Version { get; }
public string Name { get; }
public string FullName { get; }
@@ -83,8 +86,10 @@ public OsInfo(IEnumerable versionAdapters, Logger logger)
FullName = Name;
}
- Environment.SetEnvironmentVariable("OS_NAME", Name);
- Environment.SetEnvironmentVariable("OS_VERSION", Version);
+ if (IsLinux && File.Exists("/proc/1/cgroup") && File.ReadAllText("/proc/1/cgroup").Contains("/docker/"))
+ {
+ IsDocker = true;
+ }
}
}
@@ -93,6 +98,7 @@ public interface IOsInfo
string Version { get; }
string Name { get; }
string FullName { get; }
+ bool IsDocker { get; }
}
public enum Os
diff --git a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs
index e60e5b616..f9296800a 100644
--- a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs
+++ b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs
@@ -35,7 +35,16 @@ public RuntimeInfo(IServiceProvider serviceProvider, Logger logger)
static RuntimeInfo()
{
- IsProduction = InternalIsProduction();
+ var officialBuild = InternalIsOfficialBuild();
+
+ // An build running inside of the testing environment. (Analytics disabled)
+ IsTesting = InternalIsTesting();
+
+ // An official build running outside of the testing environment. (Analytics configurable)
+ IsProduction = !IsTesting && officialBuild;
+
+ // An unofficial build running outside of the testing environment. (Analytics enabled)
+ IsDevelopment = !IsTesting && !officialBuild && !InternalIsDebug();
}
public DateTime StartTime
@@ -104,23 +113,21 @@ public RuntimeMode Mode
public bool RestartPending { get; set; }
public string ExecutingApplication { get; }
+ public static bool IsTesting { get; }
public static bool IsProduction { get; }
+ public static bool IsDevelopment { get; }
- private static bool InternalIsProduction()
+
+ private static bool InternalIsTesting()
{
- if (BuildInfo.IsDebug || Debugger.IsAttached) return false;
-
- //Official builds will never have such a high revision
- if (BuildInfo.Version.Revision > 10000) return false;
-
try
{
var lowerProcessName = Process.GetCurrentProcess().ProcessName.ToLower();
- if (lowerProcessName.Contains("vshost")) return false;
- if (lowerProcessName.Contains("nunit")) return false;
- if (lowerProcessName.Contains("jetbrain")) return false;
- if (lowerProcessName.Contains("resharper")) return false;
+ if (lowerProcessName.Contains("vshost")) return true;
+ if (lowerProcessName.Contains("nunit")) return true;
+ if (lowerProcessName.Contains("jetbrain")) return true;
+ if (lowerProcessName.Contains("resharper")) return true;
}
catch
{
@@ -130,7 +137,7 @@ private static bool InternalIsProduction()
try
{
var currentAssemblyLocation = typeof(RuntimeInfo).Assembly.Location;
- if (currentAssemblyLocation.ToLower().Contains("_output")) return false;
+ if (currentAssemblyLocation.ToLower().Contains("_output")) return true;
}
catch
{
@@ -138,13 +145,28 @@ private static bool InternalIsProduction()
}
var lowerCurrentDir = Directory.GetCurrentDirectory().ToLower();
- if (lowerCurrentDir.Contains("teamcity")) return false;
- if (lowerCurrentDir.Contains("buildagent")) return false;
- if (lowerCurrentDir.Contains("_output")) return false;
+ if (lowerCurrentDir.Contains("vsts")) return true;
+ if (lowerCurrentDir.Contains("buildagent")) return true;
+ if (lowerCurrentDir.Contains("_output")) return true;
+
+ return false;
+ }
+
+ private static bool InternalIsDebug()
+ {
+ if (BuildInfo.IsDebug || Debugger.IsAttached) return true;
+
+ return false;
+ }
+
+ private static bool InternalIsOfficialBuild()
+ {
+ //Official builds will never have such a high revision
+ if (BuildInfo.Version.Major >= 10 || BuildInfo.Version.Revision > 10000) return false;
return true;
}
public bool IsWindowsTray { get; private set; }
}
-}
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Common/Http/Dispatchers/CurlHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/CurlHttpDispatcher.cs
deleted file mode 100644
index 45574c728..000000000
--- a/src/NzbDrone.Common/Http/Dispatchers/CurlHttpDispatcher.cs
+++ /dev/null
@@ -1,342 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using System.IO.Compression;
-using System.Linq;
-using System.Net;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Text.RegularExpressions;
-using CurlSharp;
-using NLog;
-using NzbDrone.Common.EnvironmentInfo;
-using NzbDrone.Common.Extensions;
-using NzbDrone.Common.Http.Proxy;
-
-namespace NzbDrone.Common.Http.Dispatchers
-{
- public class CurlHttpDispatcher : IHttpDispatcher
- {
- private static readonly Regex ExpiryDate = new Regex(@"(expires=)([^;]+)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
-
- private readonly IHttpProxySettingsProvider _proxySettingsProvider;
- private readonly IUserAgentBuilder _userAgentBuilder;
- private readonly Logger _logger;
-
- private const string _caBundleFileName = "curl-ca-bundle.crt";
- private static readonly string _caBundleFilePath;
-
- static CurlHttpDispatcher()
- {
- if (Assembly.GetExecutingAssembly().Location.IsNotNullOrWhiteSpace())
- {
- _caBundleFilePath = Path.Combine(Assembly.GetExecutingAssembly().Location, "..", _caBundleFileName);
- }
- else
- {
- _caBundleFilePath = _caBundleFileName;
- }
- }
-
- public CurlHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, IUserAgentBuilder userAgentBuilder, Logger logger)
- {
- _proxySettingsProvider = proxySettingsProvider;
- _userAgentBuilder = userAgentBuilder;
- _logger = logger;
- }
-
- public bool CheckAvailability()
- {
- try
- {
- return CurlGlobalHandle.Instance.Initialize();
- }
- catch (Exception ex)
- {
- _logger.Trace(ex, "Initializing curl failed");
- return false;
- }
- }
-
- public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
- {
- if (!CheckAvailability())
- {
- throw new ApplicationException("Curl failed to initialize.");
- }
-
- lock (CurlGlobalHandle.Instance)
- {
- Stream responseStream = new MemoryStream();
- Stream headerStream = new MemoryStream();
-
- using (var curlEasy = new CurlEasy())
- {
- curlEasy.AutoReferer = false;
- curlEasy.WriteFunction = (b, s, n, o) =>
- {
- responseStream.Write(b, 0, s * n);
- return s * n;
- };
- curlEasy.HeaderFunction = (b, s, n, o) =>
- {
- headerStream.Write(b, 0, s * n);
- return s * n;
- };
-
- AddProxy(curlEasy, request);
-
- curlEasy.Url = request.Url.FullUri;
-
- switch (request.Method)
- {
- case HttpMethod.GET:
- curlEasy.HttpGet = true;
- break;
-
- case HttpMethod.POST:
- curlEasy.Post = true;
- break;
-
- case HttpMethod.PUT:
- curlEasy.Put = true;
- break;
-
- default:
- throw new NotSupportedException($"HttpCurl method {request.Method} not supported");
- }
- curlEasy.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent);
- curlEasy.FollowLocation = false;
-
- if (request.RequestTimeout != TimeSpan.Zero)
- {
- curlEasy.Timeout = (int)Math.Ceiling(request.RequestTimeout.TotalSeconds);
- }
-
- if (OsInfo.IsWindows)
- {
- curlEasy.CaInfo = _caBundleFilePath;
- }
-
- if (cookies != null)
- {
- curlEasy.Cookie = cookies.GetCookieHeader((Uri)request.Url);
- }
-
- if (request.ContentData != null)
- {
- curlEasy.PostFieldSize = request.ContentData.Length;
- curlEasy.SetOpt(CurlOption.CopyPostFields, new string(Array.ConvertAll(request.ContentData, v => (char)v)));
- }
-
- // Yes, we have to keep a ref to the object to prevent corrupting the unmanaged state
- using (var httpRequestHeaders = SerializeHeaders(request))
- {
- curlEasy.HttpHeader = httpRequestHeaders;
-
- var result = curlEasy.Perform();
-
- if (result != CurlCode.Ok)
- {
- switch (result)
- {
- case CurlCode.SslCaCert:
- case (CurlCode)77:
- throw new WebException(string.Format("Curl Error {0} for Url {1}, issues with your operating system SSL Root Certificate Bundle (ca-bundle).", result, curlEasy.Url));
- default:
- throw new WebException(string.Format("Curl Error {0} for Url {1}", result, curlEasy.Url));
-
- }
- }
- }
-
- var webHeaderCollection = ProcessHeaderStream(request, cookies, headerStream);
- var responseData = ProcessResponseStream(request, responseStream, webHeaderCollection);
-
- var httpHeader = new HttpHeader(webHeaderCollection);
-
- return new HttpResponse(request, httpHeader, responseData, (HttpStatusCode)curlEasy.ResponseCode);
- }
- }
- }
-
- private void AddProxy(CurlEasy curlEasy, HttpRequest request)
- {
- var proxySettings = _proxySettingsProvider.GetProxySettings(request);
- if (proxySettings != null)
-
- {
- switch (proxySettings.Type)
- {
- case ProxyType.Http:
- curlEasy.SetOpt(CurlOption.ProxyType, CurlProxyType.Http);
- curlEasy.SetOpt(CurlOption.ProxyAuth, CurlHttpAuth.Basic);
- curlEasy.SetOpt(CurlOption.ProxyUserPwd, proxySettings.Username + ":" + proxySettings.Password.ToString());
- break;
- case ProxyType.Socks4:
- curlEasy.SetOpt(CurlOption.ProxyType, CurlProxyType.Socks4);
- curlEasy.SetOpt(CurlOption.ProxyUsername, proxySettings.Username);
- curlEasy.SetOpt(CurlOption.ProxyPassword, proxySettings.Password);
- break;
- case ProxyType.Socks5:
- curlEasy.SetOpt(CurlOption.ProxyType, CurlProxyType.Socks5);
- curlEasy.SetOpt(CurlOption.ProxyUsername, proxySettings.Username);
- curlEasy.SetOpt(CurlOption.ProxyPassword, proxySettings.Password);
- break;
- }
- curlEasy.SetOpt(CurlOption.Proxy, proxySettings.Host + ":" + proxySettings.Port.ToString());
- }
- }
-
- private CurlSlist SerializeHeaders(HttpRequest request)
- {
- if (!request.Headers.ContainsKey("Accept-Encoding"))
- {
- request.Headers.Add("Accept-Encoding", "gzip");
- }
-
- if (request.Headers.ContentType == null)
- {
- request.Headers.ContentType = string.Empty;
- }
-
- var curlHeaders = new CurlSlist();
- foreach (var header in request.Headers)
- {
- curlHeaders.Append(header.Key + ": " + header.Value.ToString());
- }
-
- return curlHeaders;
- }
-
- private WebHeaderCollection ProcessHeaderStream(HttpRequest request, CookieContainer cookies, Stream headerStream)
- {
- headerStream.Position = 0;
- var headerData = headerStream.ToBytes();
- var headerString = Encoding.ASCII.GetString(headerData);
-
- var webHeaderCollection = new WebHeaderCollection();
-
- // following a redirect we could have two sets of headers, so only process the last one
- foreach (var header in headerString.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Reverse())
- {
- if (!header.Contains(":")) break;
- webHeaderCollection.Add(header);
- }
-
- var setCookie = webHeaderCollection.Get("Set-Cookie");
- if (setCookie != null && setCookie.Length > 0 && cookies != null)
- {
- try
- {
- cookies.SetCookies((Uri)request.Url, FixSetCookieHeader(setCookie));
- }
- catch (CookieException ex)
- {
- _logger.Debug("Rejected cookie {0}: {1}", ex.InnerException.Message, setCookie);
- }
- }
-
- return webHeaderCollection;
- }
-
- private string FixSetCookieHeader(string setCookie)
- {
- // fix up the date if it was malformed
- var setCookieClean = ExpiryDate.Replace(setCookie, delegate(Match match)
- {
- string shortFormat = "ddd, dd-MMM-yy HH:mm:ss";
- string longFormat = "ddd, dd-MMM-yyyy HH:mm:ss";
- DateTime dt;
- if (DateTime.TryParseExact(match.Groups[2].Value, longFormat, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out dt) ||
- DateTime.TryParseExact(match.Groups[2].Value, shortFormat, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out dt) ||
- DateTime.TryParse(match.Groups[2].Value, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out dt))
- return match.Groups[1].Value + dt.ToUniversalTime().ToString(longFormat, CultureInfo.InvariantCulture) + " GMT";
- else
- return match.Value;
- });
- return setCookieClean;
- }
-
- private byte[] ProcessResponseStream(HttpRequest request, Stream responseStream, WebHeaderCollection webHeaderCollection)
- {
- byte[] bytes = null;
- responseStream.Position = 0;
-
- if (responseStream.Length != 0)
- {
- var encoding = webHeaderCollection["Content-Encoding"];
- if (encoding != null)
- {
- if (encoding.IndexOf("gzip") != -1)
- {
- using (var zipStream = new GZipStream(responseStream, CompressionMode.Decompress))
- {
- bytes = zipStream.ToBytes();
- }
-
- webHeaderCollection.Remove("Content-Encoding");
- }
- else if (encoding.IndexOf("deflate") != -1)
- {
- using (var deflateStream = new DeflateStream(responseStream, CompressionMode.Decompress))
- {
- bytes = deflateStream.ToBytes();
- }
-
- webHeaderCollection.Remove("Content-Encoding");
- }
- }
- }
-
- if (bytes == null) bytes = responseStream.ToBytes();
- return bytes;
- }
- }
-
- internal sealed class CurlGlobalHandle : SafeHandle
- {
- public static readonly CurlGlobalHandle Instance = new CurlGlobalHandle();
-
- private bool _initialized;
- private bool _available;
-
- protected override void Dispose(bool disposing)
- {
- base.Dispose(disposing);
- }
-
- private CurlGlobalHandle()
- : base(IntPtr.Zero, true)
- {
-
- }
-
- public bool Initialize()
- {
- lock (CurlGlobalHandle.Instance)
- {
- if (_initialized)
- return _available;
-
- _initialized = true;
- _available = Curl.GlobalInit(CurlInitFlag.All) == CurlCode.Ok;
-
- return _available;
- }
- }
-
- protected override bool ReleaseHandle()
- {
- if (_initialized && _available)
- {
- Curl.GlobalCleanup();
- _available = false;
- }
- return true;
- }
-
- public override bool IsInvalid => !_initialized || !_available;
- }
-}
diff --git a/src/NzbDrone.Common/Http/Dispatchers/FallbackHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/FallbackHttpDispatcher.cs
deleted file mode 100644
index 01b60e012..000000000
--- a/src/NzbDrone.Common/Http/Dispatchers/FallbackHttpDispatcher.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using System;
-using System.Net;
-using NLog;
-using NzbDrone.Common.Cache;
-using NzbDrone.Common.EnvironmentInfo;
-
-namespace NzbDrone.Common.Http.Dispatchers
-{
- public class FallbackHttpDispatcher : IHttpDispatcher
- {
- private readonly ManagedHttpDispatcher _managedDispatcher;
- private readonly CurlHttpDispatcher _curlDispatcher;
- private readonly IPlatformInfo _platformInfo;
- private readonly Logger _logger;
-
- private readonly ICached _curlTLSFallbackCache;
-
- public FallbackHttpDispatcher(ManagedHttpDispatcher managedDispatcher, CurlHttpDispatcher curlDispatcher, ICacheManager cacheManager, IPlatformInfo platformInfo, Logger logger)
- {
- _managedDispatcher = managedDispatcher;
- _curlDispatcher = curlDispatcher;
- _platformInfo = platformInfo;
- _curlTLSFallbackCache = cacheManager.GetCache(GetType(), "curlTLSFallback");
- _logger = logger;
- }
-
- public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
- {
- if (PlatformInfo.IsMono && request.Url.Scheme == "https")
- {
- if (!_curlTLSFallbackCache.Find(request.Url.Host))
- {
- try
- {
- return _managedDispatcher.GetResponse(request, cookies);
- }
- catch (TlsFailureException)
- {
- _logger.Debug("https request failed in tls error for {0}, trying curl fallback.", request.Url.Host);
-
- _curlTLSFallbackCache.Set(request.Url.Host, true);
- }
- }
-
- if (_curlDispatcher.CheckAvailability())
- {
- return _curlDispatcher.GetResponse(request, cookies);
- }
-
- _logger.Trace("Curl not available, using default WebClient.");
- }
-
- return _managedDispatcher.GetResponse(request, cookies);
- }
- }
-}
diff --git a/src/NzbDrone.Common/Http/HttpProvider.cs b/src/NzbDrone.Common/Http/HttpProvider.cs
index 33a8ea45b..aec23cd76 100644
--- a/src/NzbDrone.Common/Http/HttpProvider.cs
+++ b/src/NzbDrone.Common/Http/HttpProvider.cs
@@ -24,7 +24,7 @@ public class HttpProvider : IHttpProvider
public HttpProvider(Logger logger)
{
_logger = logger;
- _userAgent = string.Format("Radarr {0}", BuildInfo.Version);
+ _userAgent = $"{BuildInfo.AppName}/{BuildInfo.Version.ToString(2)}";
ServicePointManager.Expect100Continue = false;
}
diff --git a/src/NzbDrone.Common/Http/TlsFailureException.cs b/src/NzbDrone.Common/Http/TlsFailureException.cs
index c1dcdd991..a6178a58d 100644
--- a/src/NzbDrone.Common/Http/TlsFailureException.cs
+++ b/src/NzbDrone.Common/Http/TlsFailureException.cs
@@ -9,10 +9,10 @@ namespace NzbDrone.Common.Http
public class TlsFailureException : WebException
{
public TlsFailureException(WebRequest request, WebException innerException)
- : base("Failed to establish secure https connection to '" + request.RequestUri + "', libcurl fallback might be unavailable.", innerException, WebExceptionStatus.SecureChannelFailure, innerException.Response)
+ : base("Failed to establish secure https connection to '" + request.RequestUri + "'.", innerException, WebExceptionStatus.SecureChannelFailure, innerException.Response)
{
}
}
-}
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Common/Http/UserAgentBuilder.cs b/src/NzbDrone.Common/Http/UserAgentBuilder.cs
index 9626cd9f7..b750cffe7 100644
--- a/src/NzbDrone.Common/Http/UserAgentBuilder.cs
+++ b/src/NzbDrone.Common/Http/UserAgentBuilder.cs
@@ -33,8 +33,8 @@ public UserAgentBuilder(IOsInfo osInfo)
var osVersion = osInfo.Version?.ToLower();
- _userAgent = $"Radarr/{BuildInfo.Version} ({osName} {osVersion})";
- _userAgentSimplified = $"Radarr/{BuildInfo.Version.ToString(2)}";
+ _userAgent = $"{BuildInfo.AppName}/{BuildInfo.Version} ({osName} {osVersion})";
+ _userAgentSimplified = $"{BuildInfo.AppName}/{BuildInfo.Version.ToString(2)}";
}
}
}
diff --git a/src/NzbDrone.Common/Instrumentation/InitializeLogger.cs b/src/NzbDrone.Common/Instrumentation/InitializeLogger.cs
new file mode 100644
index 000000000..e962f5dbb
--- /dev/null
+++ b/src/NzbDrone.Common/Instrumentation/InitializeLogger.cs
@@ -0,0 +1,28 @@
+using System.Linq;
+using NLog;
+using NLog.Fluent;
+using NzbDrone.Common.EnvironmentInfo;
+using NzbDrone.Common.Instrumentation.Extensions;
+using NzbDrone.Common.Instrumentation.Sentry;
+
+namespace NzbDrone.Common.Instrumentation
+{
+ public class InitializeLogger
+ {
+ private readonly IOsInfo _osInfo;
+
+ public InitializeLogger(IOsInfo osInfo)
+ {
+ _osInfo = osInfo;
+ }
+
+ public void Initialize()
+ {
+ var sentryTarget = LogManager.Configuration.AllTargets.OfType().FirstOrDefault();
+ if (sentryTarget != null)
+ {
+ sentryTarget.UpdateScope(_osInfo);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs b/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs
index 5829cacb7..f2ba59da4 100644
--- a/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs
+++ b/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs
@@ -58,18 +58,6 @@ public static void Register(IStartupContext startupContext, bool updateApp, bool
LogManager.ReconfigExistingLoggers();
}
- public static void UnRegisterRemoteLoggers()
- {
- var sentryRules = LogManager.Configuration.LoggingRules.Where(r => r.Targets.Any(t => t.Name == "sentryTarget"));
-
- foreach (var rules in sentryRules)
- {
- rules.Targets.Clear();
- }
-
- LogManager.ReconfigExistingLoggers();
- }
-
private static void RegisterSentry(bool updateClient)
{
string dsn;
diff --git a/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs b/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs
index fb3d87c88..47085e41f 100644
--- a/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs
+++ b/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs
@@ -8,6 +8,7 @@
using NLog.Common;
using NLog.Targets;
using NzbDrone.Common.EnvironmentInfo;
+using NzbDrone.Common.Extensions;
using Sentry;
using Sentry.Protocol;
@@ -61,6 +62,7 @@ public class SentryTarget : TargetWithLayout
{LogLevel.Warn, BreadcrumbLevel.Warning},
};
+ private readonly DateTime _startTime = DateTime.UtcNow;
private readonly IDisposable _sdk;
private bool _disposed;
@@ -68,10 +70,8 @@ public class SentryTarget : TargetWithLayout
private bool _unauthorized;
public bool FilterEvents { get; set; }
- public string UpdateBranch { get; set; }
- public Version DatabaseVersion { get; set; }
- public int DatabaseMigration { get; set; }
-
+ public bool SentryEnabled { get; set; }
+
public SentryTarget(string dsn)
{
_sdk = SentrySdk.Init(o =>
@@ -79,34 +79,81 @@ public SentryTarget(string dsn)
o.Dsn = new Dsn(dsn);
o.AttachStacktrace = true;
o.MaxBreadcrumbs = 200;
- o.SendDefaultPii = true;
+ o.SendDefaultPii = false;
o.Debug = false;
o.DiagnosticsLevel = SentryLevel.Debug;
o.Release = BuildInfo.Release;
+ if (PlatformInfo.IsMono)
+ {
+ // Mono 6.0 broke GzipStream.WriteAsync
+ // TODO: Check specific version
+ o.RequestBodyCompressionLevel = System.IO.Compression.CompressionLevel.NoCompression;
+ }
o.BeforeSend = x => SentryCleanser.CleanseEvent(x);
o.BeforeBreadcrumb = x => SentryCleanser.CleanseBreadcrumb(x);
+ o.Environment = BuildInfo.Branch;
});
- SentrySdk.ConfigureScope(scope =>
- {
- scope.User = new User {
- Username = HashUtil.AnonymousToken()
- };
-
- scope.SetTag("osfamily", OsInfo.Os.ToString());
- scope.SetTag("runtime", PlatformInfo.PlatformName);
- scope.SetTag("culture", Thread.CurrentThread.CurrentCulture.Name);
- scope.SetTag("branch", BuildInfo.Branch);
- scope.SetTag("version", BuildInfo.Version.ToString());
- scope.SetTag("production", RuntimeInfo.IsProduction.ToString());
- });
-
+ InitializeScope();
+
_debounce = new SentryDebounce();
// initialize to true and reconfigure later
// Otherwise it will default to false and any errors occuring
// before config file gets read will not be filtered
FilterEvents = true;
+ SentryEnabled = true;
+ }
+
+ public void InitializeScope()
+ {
+ SentrySdk.ConfigureScope(scope =>
+ {
+ scope.User = new User
+ {
+ Id = HashUtil.AnonymousToken()
+ };
+
+ scope.Contexts.App.Name = BuildInfo.AppName;
+ scope.Contexts.App.Version = BuildInfo.Version.ToString();
+ scope.Contexts.App.StartTime = _startTime;
+ scope.Contexts.App.Hash = HashUtil.AnonymousToken();
+ scope.Contexts.App.Build = BuildInfo.Release; // Git commit cache?
+
+ scope.SetTag("culture", Thread.CurrentThread.CurrentCulture.Name);
+ scope.SetTag("branch", BuildInfo.Branch);
+ });
+ }
+
+ public void UpdateScope(IOsInfo osInfo)
+ {
+ SentrySdk.ConfigureScope(scope =>
+ {
+ scope.SetTag("is_docker", $"{osInfo.IsDocker}");
+
+ if (osInfo.Name != null && PlatformInfo.IsMono)
+ {
+ // Sentry auto-detection of non-Windows platforms isn't that accurate on certain devices.
+ scope.Contexts.OperatingSystem.Name = osInfo.Name.FirstCharToUpper();
+ scope.Contexts.OperatingSystem.RawDescription = osInfo.FullName;
+ scope.Contexts.OperatingSystem.Version = osInfo.Version.ToString();
+ }
+ });
+ }
+
+ public void UpdateScope(Version databaseVersion, int migration, string updateBranch, IPlatformInfo platformInfo)
+ {
+ SentrySdk.ConfigureScope(scope =>
+ {
+ scope.Environment = updateBranch;
+ scope.SetTag("runtime_version", $"{PlatformInfo.PlatformName} {platformInfo.Version}");
+
+ if (databaseVersion != default(Version))
+ {
+ scope.SetTag("sqlite_version", $"{databaseVersion}");
+ scope.SetTag("database_migration", $"{migration}");
+ }
+ });
}
private void OnError(Exception ex)
@@ -191,7 +238,7 @@ public bool IsSentryMessage(LogEventInfo logEvent)
protected override void Write(LogEventInfo logEvent)
{
- if (_unauthorized)
+ if (_unauthorized || !SentryEnabled)
{
return;
}
@@ -227,27 +274,12 @@ protected override void Write(LogEventInfo logEvent)
{
Level = LoggingLevelMap[logEvent.Level],
Logger = logEvent.LoggerName,
- Message = logEvent.FormattedMessage,
- Environment = UpdateBranch
+ Message = logEvent.FormattedMessage
};
sentryEvent.SetExtras(extras);
sentryEvent.SetFingerprint(fingerPrint);
- // this can't be in the constructor as at that point OsInfo won't have
- // populated these values yet
- var osName = Environment.GetEnvironmentVariable("OS_NAME");
- var osVersion = Environment.GetEnvironmentVariable("OS_VERSION");
- var isDocker = Environment.GetEnvironmentVariable("OS_IS_DOCKER");
- var runTimeVersion = Environment.GetEnvironmentVariable("RUNTIME_VERSION");
-
- sentryEvent.SetTag("os_name", osName);
- sentryEvent.SetTag("os_version", $"{osName} {osVersion}");
- sentryEvent.SetTag("is_docker", isDocker);
- sentryEvent.SetTag("runtime_version", $"{PlatformInfo.PlatformName} {runTimeVersion}");
- sentryEvent.SetTag("sqlite_version", $"{DatabaseVersion}");
- sentryEvent.SetTag("database_migration", $"{DatabaseMigration}");
-
SentrySdk.CaptureEvent(sentryEvent);
}
catch (Exception e)
diff --git a/src/NzbDrone.Common/Processes/ProcessProvider.cs b/src/NzbDrone.Common/Processes/ProcessProvider.cs
index 2e52895b2..19a2c9a13 100644
--- a/src/NzbDrone.Common/Processes/ProcessProvider.cs
+++ b/src/NzbDrone.Common/Processes/ProcessProvider.cs
@@ -328,6 +328,8 @@ private List GetProcessesByName(string name)
var monoProcesses = Process.GetProcessesByName("mono")
.Union(Process.GetProcessesByName("mono-sgen"))
+ .Union(Process.GetProcessesByName("mono-sgen32"))
+ .Union(Process.GetProcessesByName("mono-sgen64"))
.Where(process =>
process.Modules.Cast()
.Any(module =>
diff --git a/src/NzbDrone.Common/Radarr.Common.csproj b/src/NzbDrone.Common/Radarr.Common.csproj
index ae6bae20a..e5b932a32 100644
--- a/src/NzbDrone.Common/Radarr.Common.csproj
+++ b/src/NzbDrone.Common/Radarr.Common.csproj
@@ -11,9 +11,6 @@
-
-
-
diff --git a/src/NzbDrone.Console/ConsoleApp.cs b/src/NzbDrone.Console/ConsoleApp.cs
index f5920f08c..69cfc6393 100644
--- a/src/NzbDrone.Console/ConsoleApp.cs
+++ b/src/NzbDrone.Console/ConsoleApp.cs
@@ -5,6 +5,7 @@
using NzbDrone.Common.Exceptions;
using NzbDrone.Common.Instrumentation;
using Radarr.Host;
+using Radarr.Host.AccessControl;
namespace NzbDrone.Console
{
@@ -50,6 +51,13 @@ public static void Main(string[] args)
Logger.Fatal(ex.Message + ". This can happen if another instance of Radarr is already running another application is using the same port (default: 7878) or the user has insufficient permissions");
Exit(ExitCodes.RecoverableFailure);
}
+ catch (RemoteAccessException ex)
+ {
+ System.Console.WriteLine("");
+ System.Console.WriteLine("");
+ Logger.Fatal(ex, "EPIC FAIL!");
+ Exit(ExitCodes.Normal);
+ }
catch (Exception ex)
{
System.Console.WriteLine("");
diff --git a/src/NzbDrone.Core.Test/Framework/CoreTest.cs b/src/NzbDrone.Core.Test/Framework/CoreTest.cs
index 36efd648e..cd7e2f93b 100644
--- a/src/NzbDrone.Core.Test/Framework/CoreTest.cs
+++ b/src/NzbDrone.Core.Test/Framework/CoreTest.cs
@@ -30,10 +30,9 @@ protected void UseRealHttp()
Mocker.SetConstant(new HttpProxySettingsProvider(Mocker.Resolve()));
Mocker.SetConstant(new ManagedWebProxyFactory(Mocker.Resolve()));
- Mocker.SetConstant(new ManagedHttpDispatcher(Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), TestLogger));
- Mocker.SetConstant(new CurlHttpDispatcher(Mocker.Resolve(), Mocker.Resolve(), TestLogger));
+ Mocker.SetConstant(new ManagedHttpDispatcher(Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), TestLogger));
Mocker.SetConstant(new HttpProvider(TestLogger));
- Mocker.SetConstant(new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), TestLogger));
+ Mocker.SetConstant(new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), TestLogger));
Mocker.SetConstant(new RadarrCloudRequestBuilder());
}
diff --git a/src/NzbDrone.Core.Test/Framework/DbTest.cs b/src/NzbDrone.Core.Test/Framework/DbTest.cs
index cd2232fa6..92772d4ee 100644
--- a/src/NzbDrone.Core.Test/Framework/DbTest.cs
+++ b/src/NzbDrone.Core.Test/Framework/DbTest.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Data.SQLite;
using System.IO;
using System.Linq;
using FluentMigrator.Runner;
@@ -99,7 +100,6 @@ protected void SetupContainer()
{
WithTempAsAppPath();
- Mocker.SetConstant(Mocker.Resolve());
Mocker.SetConstant(Mocker.Resolve());
Mocker.SetConstant(Mocker.Resolve());
@@ -116,22 +116,15 @@ public virtual void SetupDb()
[TearDown]
public void TearDown()
{
- if (TestFolderInfo != null && Directory.Exists(TestFolderInfo.AppDataFolder))
+ // Make sure there are no lingering connections. (When this happens it means we haven't disposed something properly)
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ SQLiteConnection.ClearAllPools();
+
+ if (TestFolderInfo != null)
{
- var files = Directory.GetFiles(TestFolderInfo.AppDataFolder);
-
- foreach (var file in files)
- {
- try
- {
- File.Delete(file);
- }
- catch (Exception)
- {
-
- }
- }
+ DeleteTempFolder(TestFolderInfo.AppDataFolder);
}
}
}
-}
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/DotnetVersionCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/DotnetVersionCheckFixture.cs
new file mode 100644
index 000000000..fefe82c57
--- /dev/null
+++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/DotnetVersionCheckFixture.cs
@@ -0,0 +1,57 @@
+using System;
+using NUnit.Framework;
+using NzbDrone.Common.EnvironmentInfo;
+using NzbDrone.Core.HealthCheck.Checks;
+using NzbDrone.Core.Test.Framework;
+
+namespace NzbDrone.Core.Test.HealthCheck.Checks
+{
+ [TestFixture]
+ public class DotnetVersionCheckFixture : CoreTest
+ {
+ private void GivenOutput(string version)
+ {
+ WindowsOnly();
+
+ Mocker.GetMock()
+ .SetupGet(s => s.Version)
+ .Returns(new Version(version));
+ }
+
+ [TestCase("4.7.2")]
+ [TestCase("4.8")]
+ public void should_return_ok(string version)
+ {
+ GivenOutput(version);
+
+ Subject.Check().ShouldBeOk();
+ }
+
+ [TestCase("4.6.2")]
+ [TestCase("4.7")]
+ [TestCase("4.7.1")]
+ public void should_return_notice(string version)
+ {
+ GivenOutput(version);
+
+ Subject.Check().ShouldBeNotice();
+ }
+
+ public void should_return_warning(string version)
+ {
+ GivenOutput(version);
+
+ Subject.Check().ShouldBeWarning();
+ }
+
+ [TestCase("4.5")]
+ [TestCase("4.5.2")]
+ [TestCase("4.6.1")]
+ public void should_return_error(string version)
+ {
+ GivenOutput(version);
+
+ Subject.Check().ShouldBeError();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/HealthCheckFixtureExtensions.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/HealthCheckFixtureExtensions.cs
index 5654fa388..7488ff08a 100644
--- a/src/NzbDrone.Core.Test/HealthCheck/Checks/HealthCheckFixtureExtensions.cs
+++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/HealthCheckFixtureExtensions.cs
@@ -11,6 +11,16 @@ public static void ShouldBeOk(this Core.HealthCheck.HealthCheck result)
result.Type.Should().Be(HealthCheckResult.Ok);
}
+ public static void ShouldBeNotice(this Core.HealthCheck.HealthCheck result, string message = null)
+ {
+ result.Type.Should().Be(HealthCheckResult.Notice);
+
+ if (message.IsNotNullOrWhiteSpace())
+ {
+ result.Message.Should().Contain(message);
+ }
+ }
+
public static void ShouldBeWarning(this Core.HealthCheck.HealthCheck result, string message = null)
{
result.Type.Should().Be(HealthCheckResult.Warning);
diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs
index 21690a20b..b95063928 100644
--- a/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs
+++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs
@@ -18,14 +18,9 @@ private void GivenOutput(string version)
.Returns(new Version(version));
}
-
- [TestCase("4.6")]
- [TestCase("4.4.2")]
- [TestCase("4.6")]
- [TestCase("4.8")]
- [TestCase("5.0")]
- [TestCase("5.2")]
- [TestCase("5.4")]
+
+ [TestCase("5.18")]
+ [TestCase("5.20")]
public void should_return_ok(string version)
{
GivenOutput(version);
@@ -33,6 +28,23 @@ public void should_return_ok(string version)
Subject.Check().ShouldBeOk();
}
+ [TestCase("5.16")]
+ public void should_return_notice(string version)
+ {
+ GivenOutput(version);
+
+ Subject.Check().ShouldBeNotice();
+ }
+
+ [TestCase("5.4")]
+ [TestCase("5.8")]
+ public void should_return_warning(string version)
+ {
+ GivenOutput(version);
+
+ Subject.Check().ShouldBeWarning();
+ }
+
[TestCase("2.10.2")]
[TestCase("2.10.8.1")]
[TestCase("3.0.0.1")]
@@ -44,14 +56,6 @@ public void should_return_ok(string version)
[TestCase("3.10")]
[TestCase("4.0.0.0")]
[TestCase("4.2")]
- public void should_return_warning(string version)
- {
- GivenOutput(version);
-
- Subject.Check().ShouldBeWarning();
- }
-
-
[TestCase("4.4.0")]
[TestCase("4.4.1")]
public void should_return_error(string version)
diff --git a/src/NzbDrone.Core.Test/Messaging/Commands/CommandExecutorFixture.cs b/src/NzbDrone.Core.Test/Messaging/Commands/CommandExecutorFixture.cs
index 4a039e699..8acff9714 100644
--- a/src/NzbDrone.Core.Test/Messaging/Commands/CommandExecutorFixture.cs
+++ b/src/NzbDrone.Core.Test/Messaging/Commands/CommandExecutorFixture.cs
@@ -1,121 +1,224 @@
-//using System;
-//using System.Collections.Generic;
-//using Moq;
-//using NUnit.Framework;
-//using NzbDrone.Common;
-//using NzbDrone.Core.Messaging.Commands;
-//using NzbDrone.Core.Messaging.Commands.Tracking;
-//using NzbDrone.Core.Messaging.Events;
-//using NzbDrone.Test.Common;
-//
-//namespace NzbDrone.Core.Test.Messaging.Commands
-//{
-// [TestFixture]
-// public class CommandExecutorFixture : TestBase
-// {
-// private Mock> _executorA;
-// private Mock> _executorB;
-//
-// [SetUp]
-// public void Setup()
-// {
-// _executorA = new Mock>();
-// _executorB = new Mock>();
-//
-// Mocker.GetMock()
-// .Setup(c => c.Build(typeof(IExecute)))
-// .Returns(_executorA.Object);
-//
-// Mocker.GetMock()
-// .Setup(c => c.Build(typeof(IExecute)))
-// .Returns(_executorB.Object);
-//
-//
-// Mocker.GetMock()
-// .Setup(c => c.FindExisting(It.IsAny()))
-// .Returns(null);
-// }
-//
-// [Test]
-// public void should_publish_command_to_executor()
-// {
-// var commandA = new CommandA();
-//
-// Subject.Push(commandA);
-//
-// _executorA.Verify(c => c.Execute(commandA), Times.Once());
-// }
-//
-// [Test]
-// public void should_publish_command_by_with_optional_arg_using_name()
-// {
-// Mocker.GetMock().Setup(c => c.GetImplementations(typeof(Command)))
-// .Returns(new List { typeof(CommandA), typeof(CommandB) });
-//
-// Subject.Push(typeof(CommandA).FullName);
-// _executorA.Verify(c => c.Execute(It.IsAny()), Times.Once());
-// }
-//
-//
-// [Test]
-// public void should_not_publish_to_incompatible_executor()
-// {
-// var commandA = new CommandA();
-//
-// Subject.Push(commandA);
-//
-// _executorA.Verify(c => c.Execute(commandA), Times.Once());
-// _executorB.Verify(c => c.Execute(It.IsAny()), Times.Never());
-// }
-//
-// [Test]
-// public void broken_executor_should_throw_the_exception()
-// {
-// var commandA = new CommandA();
-//
-// _executorA.Setup(c => c.Execute(It.IsAny()))
-// .Throws(new NotImplementedException());
-//
-// Assert.Throws(() => Subject.Push(commandA));
-// }
-//
-//
-// [Test]
-// public void broken_executor_should_publish_executed_event()
-// {
-// var commandA = new CommandA();
-//
-// _executorA.Setup(c => c.Execute(It.IsAny()))
-// .Throws(new NotImplementedException());
-//
-// Assert.Throws(() => Subject.Push(commandA));
-//
-// VerifyEventPublished();
-// }
-//
-// [Test]
-// public void should_publish_executed_event_on_success()
-// {
-// var commandA = new CommandA();
-// Subject.Push(commandA);
-//
-// VerifyEventPublished();
-// }
-// }
-//
-// public class CommandA : Command
-// {
-// public CommandA(int id = 0)
-// {
-// }
-// }
-//
-// public class CommandB : Command
-// {
-//
-// public CommandB()
-// {
-// }
-// }
-//
-//}
\ No newline at end of file
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Threading;
+using Moq;
+using NUnit.Framework;
+using NzbDrone.Common;
+using NzbDrone.Core.Lifecycle;
+using NzbDrone.Core.Messaging.Commands;
+using NzbDrone.Core.Messaging.Events;
+using NzbDrone.Test.Common;
+
+namespace NzbDrone.Core.Test.Messaging.Commands
+{
+ [TestFixture]
+ public class CommandExecutorFixture : TestBase
+ {
+ private CommandQueue _commandQueue;
+ private Mock> _executorA;
+ private Mock> _executorB;
+
+ [SetUp]
+ public void Setup()
+ {
+ _executorA = new Mock>();
+ _executorB = new Mock>();
+
+ Mocker.GetMock()
+ .Setup(c => c.Build(typeof(IExecute)))
+ .Returns(_executorA.Object);
+
+ Mocker.GetMock()
+ .Setup(c => c.Build(typeof(IExecute)))
+ .Returns(_executorB.Object);
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ Subject.Handle(new ApplicationShutdownRequested());
+
+ // Give the threads a bit of time to shut down.
+ Thread.Sleep(10);
+ }
+
+ private void GivenCommandQueue()
+ {
+ _commandQueue = new CommandQueue();
+
+ Mocker.GetMock()
+ .Setup(s => s.Queue(It.IsAny()))
+ .Returns(_commandQueue.GetConsumingEnumerable);
+ }
+
+ private void QueueAndWaitForExecution(CommandModel commandModel, bool waitPublish = false)
+ {
+ var waitEventComplete = new ManualResetEventSlim();
+ var waitEventPublish = new ManualResetEventSlim();
+
+ Mocker.GetMock()
+ .Setup(s => s.Complete(It.Is(c => c == commandModel), It.IsAny()))
+ .Callback(() => waitEventComplete.Set());
+
+ Mocker.GetMock()
+ .Setup(s => s.Fail(It.Is(c => c == commandModel), It.IsAny(), It.IsAny()))
+ .Callback(() => waitEventComplete.Set());
+
+ Mocker.GetMock()
+ .Setup(s => s.PublishEvent(It.IsAny()))
+ .Callback(() => waitEventPublish.Set());
+
+ _commandQueue.Add(commandModel);
+
+ if (!waitEventComplete.Wait(2000))
+ {
+ Assert.Fail("Command did not Complete/Fail within 2 sec");
+ }
+
+ if (waitPublish && !waitEventPublish.Wait(500))
+ {
+ Assert.Fail("Command did not Publish within 500 msec");
+ }
+ }
+
+ [Test]
+ public void should_start_executor_threads()
+ {
+ Subject.Handle(new ApplicationStartedEvent());
+
+ Mocker.GetMock()
+ .Verify(v => v.Queue(It.IsAny()), Times.AtLeastOnce());
+ }
+
+ [Test]
+ public void should_execute_on_executor()
+ {
+ GivenCommandQueue();
+ var commandA = new CommandA();
+ var commandModel = new CommandModel
+ {
+ Body = commandA
+ };
+
+ Subject.Handle(new ApplicationStartedEvent());
+
+ QueueAndWaitForExecution(commandModel);
+
+ _executorA.Verify(c => c.Execute(commandA), Times.Once());
+ }
+
+ [Test]
+ public void should_not_execute_on_incompatible_executor()
+ {
+ GivenCommandQueue();
+ var commandA = new CommandA();
+ var commandModel = new CommandModel
+ {
+ Body = commandA
+ };
+
+ Subject.Handle(new ApplicationStartedEvent());
+
+ QueueAndWaitForExecution(commandModel);
+
+ _executorA.Verify(c => c.Execute(commandA), Times.Once());
+ _executorB.Verify(c => c.Execute(It.IsAny()), Times.Never());
+ }
+
+ [Test]
+ public void broken_executor_should_publish_executed_event()
+ {
+ GivenCommandQueue();
+ var commandA = new CommandA();
+ var commandModel = new CommandModel
+ {
+ Body = commandA
+ };
+
+ _executorA.Setup(s => s.Execute(It.IsAny()))
+ .Throws(new NotImplementedException());
+
+ Subject.Handle(new ApplicationStartedEvent());
+
+ QueueAndWaitForExecution(commandModel);
+
+ VerifyEventPublished();
+
+ ExceptionVerification.WaitForErrors(1, 500);
+ }
+
+ [Test]
+ public void should_publish_executed_event_on_success()
+ {
+ GivenCommandQueue();
+ var commandA = new CommandA();
+ var commandModel = new CommandModel
+ {
+ Body = commandA
+ };
+
+ Subject.Handle(new ApplicationStartedEvent());
+
+ QueueAndWaitForExecution(commandModel);
+
+ VerifyEventPublished();
+ }
+
+ [Test]
+ public void should_use_completion_message()
+ {
+ GivenCommandQueue();
+ var commandA = new CommandA();
+ var commandModel = new CommandModel
+ {
+ Body = commandA
+ };
+
+ Subject.Handle(new ApplicationStartedEvent());
+
+ QueueAndWaitForExecution(commandModel);
+
+ Mocker.GetMock()
+ .Verify(s => s.Complete(It.Is(c => c == commandModel), commandA.CompletionMessage), Times.Once());
+ }
+
+ [Test]
+ public void should_use_last_progress_message_if_completion_message_is_null()
+ {
+ GivenCommandQueue();
+ var commandB = new CommandB();
+ var commandModel = new CommandModel
+ {
+ Body = commandB,
+ Message = "Do work"
+ };
+
+ Subject.Handle(new ApplicationStartedEvent());
+
+ QueueAndWaitForExecution(commandModel);
+
+ Mocker.GetMock()
+ .Verify(s => s.Complete(It.Is(c => c == commandModel), commandModel.Message), Times.Once());
+ }
+ }
+
+ public class CommandA : Command
+ {
+ public CommandA(int id = 0)
+ {
+ }
+ }
+
+ public class CommandB : Command
+ {
+
+ public CommandB()
+ {
+
+ }
+
+ public override string CompletionMessage => null;
+ }
+
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Core.Test/MetadataSource/SkyHook/SkyHookProxySearchFixture.cs b/src/NzbDrone.Core.Test/MetadataSource/SkyHook/SkyHookProxySearchFixture.cs
index e97716bac..6b047f50c 100644
--- a/src/NzbDrone.Core.Test/MetadataSource/SkyHook/SkyHookProxySearchFixture.cs
+++ b/src/NzbDrone.Core.Test/MetadataSource/SkyHook/SkyHookProxySearchFixture.cs
@@ -18,7 +18,8 @@ public void Setup()
}
[TestCase("Prometheus", "Prometheus")]
- [TestCase("The Man from U.N.C.L.E.", "The Man from U.N.C.L.E.")]
+ // TODO: TMDB Doesn't like when we clean periods from this
+ // [TestCase("The Man from U.N.C.L.E.", "The Man from U.N.C.L.E.")]
[TestCase("imdb:tt2527336", "Star Wars: The Last Jedi")]
[TestCase("imdb:tt2798920", "Annihilation")]
public void successful_search(string title, string expected)
diff --git a/src/NzbDrone.Core.Test/MovieTests/ShouldRefreshMovieFixture.cs b/src/NzbDrone.Core.Test/MovieTests/ShouldRefreshMovieFixture.cs
index e8d9bc037..208515664 100644
--- a/src/NzbDrone.Core.Test/MovieTests/ShouldRefreshMovieFixture.cs
+++ b/src/NzbDrone.Core.Test/MovieTests/ShouldRefreshMovieFixture.cs
@@ -42,9 +42,9 @@ private void GivenMovieLastRefreshedYesterday()
_movie.LastInfoSync = DateTime.UtcNow.AddDays(-1);
}
- private void GivenMovieLastRefreshedHalfADayAgo()
+ private void GivenMovieLastRefreshedADayAgo()
{
- _movie.LastInfoSync = DateTime.UtcNow.AddHours(-12);
+ _movie.LastInfoSync = DateTime.UtcNow.AddHours(-24);
}
private void GivenMovieLastRefreshedRecently()
@@ -58,15 +58,15 @@ private void GivenRecentlyReleased()
}
[Test]
- public void should_return_true_if_in_cinemas_movie_last_refreshed_more_than_6_hours_ago()
+ public void should_return_true_if_in_cinemas_movie_last_refreshed_more_than_12_hours_ago()
{
- GivenMovieLastRefreshedHalfADayAgo();
+ GivenMovieLastRefreshedADayAgo();
Subject.ShouldRefresh(_movie).Should().BeTrue();
}
[Test]
- public void should_return_false_if_in_cinemas_movie_last_refreshed_less_than_6_hours_ago()
+ public void should_return_false_if_in_cinemas_movie_last_refreshed_less_than_12_hours_ago()
{
GivenMovieLastRefreshedRecently();
diff --git a/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs b/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs
index cdf7e0f47..5e336420b 100644
--- a/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs
+++ b/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs
@@ -37,6 +37,7 @@ private void WithNonExpired()
public void Setup()
{
Mocker.GetMock().SetupGet(s => s.RecycleBin).Returns(RecycleBin);
+ Mocker.GetMock().SetupGet(s => s.RecycleBinCleanupDays).Returns(7);
Mocker.GetMock().Setup(s => s.GetDirectories(RecycleBin))
.Returns(new [] { @"C:\Test\RecycleBin\Folder1", @"C:\Test\RecycleBin\Folder2", @"C:\Test\RecycleBin\Folder3" });
diff --git a/src/NzbDrone.Core.Test/Radarr.Core.Test.csproj b/src/NzbDrone.Core.Test/Radarr.Core.Test.csproj
index ca456f446..c537fe15e 100644
--- a/src/NzbDrone.Core.Test/Radarr.Core.Test.csproj
+++ b/src/NzbDrone.Core.Test/Radarr.Core.Test.csproj
@@ -15,6 +15,9 @@
Files\1024.png
PreserveNewest
+
+ ..\Libraries\Sqlite\System.Data.SQLite.dll
+
PreserveNewest
diff --git a/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs b/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs
index 8f26183d3..bd04a2b51 100644
--- a/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs
+++ b/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs
@@ -87,6 +87,16 @@ private void GivenInstallScript(string path)
.Returns(true);
}
+ [Test]
+ public void should_not_update_if_inside_docker()
+ {
+ Mocker.GetMock().Setup(x => x.IsDocker).Returns(true);
+
+ Subject.Invoking(x => x.Execute(new ApplicationUpdateCommand()))
+ .Should().Throw()
+ .WithMessage("Updating is disabled inside a docker container. Please update the container image.");
+ }
+
[Test]
public void should_delete_sandbox_before_update_if_folder_exists()
{
diff --git a/src/NzbDrone.Core/Analytics/AnalyticsService.cs b/src/NzbDrone.Core/Analytics/AnalyticsService.cs
index dfd9d8980..94dedf497 100644
--- a/src/NzbDrone.Core/Analytics/AnalyticsService.cs
+++ b/src/NzbDrone.Core/Analytics/AnalyticsService.cs
@@ -1,22 +1,40 @@
-using NzbDrone.Common.EnvironmentInfo;
+using System;
+using System.Linq;
+using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration;
+using NzbDrone.Core.Datastore;
+using NzbDrone.Core.History;
namespace NzbDrone.Core.Analytics
{
public interface IAnalyticsService
{
bool IsEnabled { get; }
+ bool InstallIsActive { get; }
}
public class AnalyticsService : IAnalyticsService
{
private readonly IConfigFileProvider _configFileProvider;
+ private readonly IHistoryService _historyService;
- public AnalyticsService(IConfigFileProvider configFileProvider)
+ public AnalyticsService(IHistoryService historyService, IConfigFileProvider configFileProvider)
{
_configFileProvider = configFileProvider;
+ _historyService = historyService;
}
- public bool IsEnabled => _configFileProvider.AnalyticsEnabled;
+ public bool IsEnabled => _configFileProvider.AnalyticsEnabled && RuntimeInfo.IsProduction || RuntimeInfo.IsDevelopment;
+
+ public bool InstallIsActive
+ {
+ get
+ {
+ var lastRecord = _historyService.Paged(new PagingSpec() { Page = 0, PageSize = 1, SortKey = "date", SortDirection = SortDirection.Descending });
+ var monthAgo = DateTime.UtcNow.AddMonths(-1);
+
+ return lastRecord.Records.Any(v => v.Date > monthAgo);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs
index dddf3da82..c41936d61 100644
--- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs
+++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs
@@ -34,6 +34,7 @@ public interface IConfigFileProvider : IHandleAsync,
bool AnalyticsEnabled { get; }
string LogLevel { get; }
string ConsoleLogLevel { get; }
+ bool FilterSentryEvents { get; }
string Branch { get; }
string ApiKey { get; }
string SslCertHash { get; }
@@ -182,7 +183,7 @@ public AuthenticationType AuthenticationMethod
public string LogLevel => GetValue("LogLevel", "info");
public string ConsoleLogLevel => GetValue("ConsoleLogLevel", string.Empty, persist: false);
-
+ public bool FilterSentryEvents => GetValueBoolean("FilterSentryEvents", true, persist: false);
public string SslCertHash => GetValue("SslCertHash", "");
public string UrlBase
@@ -364,11 +365,6 @@ public void HandleAsync(ApplicationStartedEvent message)
{
EnsureDefaultConfigFile();
DeleteOldValues();
-
- if (!AnalyticsEnabled)
- {
- NzbDroneLogger.UnRegisterRemoteLoggers();
- }
}
public void Execute(ResetApiKeyCommand message)
diff --git a/src/NzbDrone.Core/Datastore/CorruptDatabaseException.cs b/src/NzbDrone.Core/Datastore/CorruptDatabaseException.cs
index 1d8b6696d..4493ca1b5 100644
--- a/src/NzbDrone.Core/Datastore/CorruptDatabaseException.cs
+++ b/src/NzbDrone.Core/Datastore/CorruptDatabaseException.cs
@@ -3,7 +3,7 @@
namespace NzbDrone.Core.Datastore
{
- public class CorruptDatabaseException : NzbDroneException
+ public class CorruptDatabaseException : RadarrStartupException
{
public CorruptDatabaseException(string message, params object[] args) : base(message, args)
{
diff --git a/src/NzbDrone.Core/Datastore/Database.cs b/src/NzbDrone.Core/Datastore/Database.cs
index 2a8417ed6..1ff4fba49 100644
--- a/src/NzbDrone.Core/Datastore/Database.cs
+++ b/src/NzbDrone.Core/Datastore/Database.cs
@@ -9,6 +9,7 @@ public interface IDatabase
{
IDataMapper GetDataMapper();
Version Version { get; }
+ int Migration { get; }
void Vacuum();
}
@@ -42,6 +43,16 @@ public Version Version
}
}
+ public int Migration
+ {
+ get
+ {
+ var migration = _datamapperFactory()
+ .ExecuteScalar("SELECT version from VersionInfo ORDER BY version DESC LIMIT 1").ToString();
+ return Convert.ToInt32(migration);
+ }
+ }
+
public void Vacuum()
{
try
diff --git a/src/NzbDrone.Core/Datastore/DbFactory.cs b/src/NzbDrone.Core/Datastore/DbFactory.cs
index fd41b8145..07e406595 100644
--- a/src/NzbDrone.Core/Datastore/DbFactory.cs
+++ b/src/NzbDrone.Core/Datastore/DbFactory.cs
@@ -6,6 +6,7 @@
using NzbDrone.Common.Composition;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
+using NzbDrone.Common.Exceptions;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.Datastore.Migration.Framework;
@@ -124,7 +125,11 @@ private void CreateMain(string connectionString, MigrationContext migrationConte
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://github.com/Sonarr/Sonarr/wiki/FAQ#i-use-sonarr-on-a-mac-and-it-suddenly-stopped-working-what-happened", e, fileName);
}
- throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://github.com/Sonarr/Sonarr/wiki/FAQ#i-am-getting-an-error-database-disk-image-is-malformed", e, fileName);
+ throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://github.com/Lidarr/Lidarr/wiki/FAQ#i-am-getting-an-error-database-disk-image-is-malformed", e, fileName);
+ }
+ catch (Exception e)
+ {
+ throw new RadarrStartupException(e, "Error creating main database");
}
}
@@ -154,6 +159,10 @@ private void CreateLog(string connectionString, MigrationContext migrationContex
_migrationController.Migrate(connectionString, migrationContext);
}
+ catch (Exception e)
+ {
+ throw new RadarrStartupException(e, "Error creating log database");
+ }
}
}
}
diff --git a/src/NzbDrone.Core/Datastore/LogDatabase.cs b/src/NzbDrone.Core/Datastore/LogDatabase.cs
index c454e9997..e1c9c3a20 100644
--- a/src/NzbDrone.Core/Datastore/LogDatabase.cs
+++ b/src/NzbDrone.Core/Datastore/LogDatabase.cs
@@ -24,6 +24,8 @@ public IDataMapper GetDataMapper()
public Version Version => _database.Version;
+ public int Migration => _database.Migration;
+
public void Vacuum()
{
_database.Vacuum();
diff --git a/src/NzbDrone.Core/Datastore/MainDatabase.cs b/src/NzbDrone.Core/Datastore/MainDatabase.cs
index 8ce09eaf2..869c3a6da 100644
--- a/src/NzbDrone.Core/Datastore/MainDatabase.cs
+++ b/src/NzbDrone.Core/Datastore/MainDatabase.cs
@@ -24,6 +24,8 @@ public IDataMapper GetDataMapper()
public Version Version => _database.Version;
+ public int Migration => _database.Migration;
+
public void Vacuum()
{
_database.Vacuum();
diff --git a/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs b/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs
index 793725e9f..2e1a2d2ab 100644
--- a/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs
+++ b/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs
@@ -57,7 +57,8 @@ public void Migrate(string connectionString, MigrationContext migrationContext)
SQLiteConnection.ClearAllPools();
throw;
}
-
+
+ processor.Dispose();
sw.Stop();
diff --git a/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs b/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs
index 5d44be05f..28715fc12 100644
--- a/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs
+++ b/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs
@@ -237,7 +237,7 @@ private ValidationFailure TestConnection()
}
catch (WebException ex)
{
- _logger.Error(ex, "Unble to test connection");
+ _logger.Error(ex, "Unable to test connection");
switch (ex.Status)
{
case WebExceptionStatus.ConnectFailure:
diff --git a/src/NzbDrone.Core/HealthCheck/Checks/DotnetVersionCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/DotnetVersionCheck.cs
new file mode 100644
index 000000000..60787d808
--- /dev/null
+++ b/src/NzbDrone.Core/HealthCheck/Checks/DotnetVersionCheck.cs
@@ -0,0 +1,52 @@
+using System;
+using NLog;
+using NzbDrone.Common.EnvironmentInfo;
+
+namespace NzbDrone.Core.HealthCheck.Checks
+{
+ public class DotnetVersionCheck : HealthCheckBase
+ {
+ private readonly IPlatformInfo _platformInfo;
+ private readonly Logger _logger;
+
+ public DotnetVersionCheck(IPlatformInfo platformInfo, Logger logger)
+ {
+ _platformInfo = platformInfo;
+ _logger = logger;
+ }
+
+ public override HealthCheck Check()
+ {
+ if (!PlatformInfo.IsDotNet)
+ {
+ return new HealthCheck(GetType());
+ }
+
+ var dotnetVersion = _platformInfo.Version;
+
+ // Target .Net version, which would allow us to increase our target framework
+ var targetVersion = new Version("4.7.2");
+ if (dotnetVersion >= targetVersion)
+ {
+ _logger.Debug("Dotnet version is {0} or better: {1}", targetVersion, dotnetVersion);
+ return new HealthCheck(GetType());
+ }
+
+ // Supported .net version but below our desired target
+ var stableVersion = new Version("4.6.2");
+ if (dotnetVersion >= stableVersion)
+ {
+ _logger.Debug("Dotnet version is {0} or better: {1}", stableVersion, dotnetVersion);
+ return new HealthCheck(GetType(), HealthCheckResult.Notice,
+ $"Currently installed .Net Framework {dotnetVersion} is supported but we recommend upgrading to at least {targetVersion}.",
+ "#currently-installed-net-framework-is-supported-but-upgrading-is-recommended");
+ }
+
+ return new HealthCheck(GetType(), HealthCheckResult.Error,
+ $"Currently installed .Net Framework {dotnetVersion} is old and unsupported. Please upgrade the .Net Framework to at least {targetVersion}.",
+ "#currently-installed-net-framework-is-old-and-unsupported");
+ }
+
+ public override bool CheckOnSchedule => false;
+ }
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Core/HealthCheck/Checks/MonoTlsCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/MonoTlsCheck.cs
index e4ce38beb..fffcc8c14 100644
--- a/src/NzbDrone.Core/HealthCheck/Checks/MonoTlsCheck.cs
+++ b/src/NzbDrone.Core/HealthCheck/Checks/MonoTlsCheck.cs
@@ -2,7 +2,9 @@
using System.Linq;
using System.Reflection;
using NLog;
+using NLog.Fluent;
using NzbDrone.Common.EnvironmentInfo;
+using NzbDrone.Common.Instrumentation.Extensions;
namespace NzbDrone.Core.HealthCheck.Checks
{
@@ -26,11 +28,14 @@ public override HealthCheck Check()
var monoVersion = _platformInfo.Version;
- if (monoVersion >= new Version("5.0.0") && Environment.GetEnvironmentVariable("MONO_TLS_PROVIDER") == "legacy")
+ if (monoVersion >= new Version("5.8.0") && Environment.GetEnvironmentVariable("MONO_TLS_PROVIDER") == "legacy")
{
- // Mono 5.0 still has issues in combination with libmediainfo, so disabling this check for now.
- //_logger.Debug("Mono version 5.0.0 or higher and legacy TLS provider is selected, recommending user to switch to btls.");
- //return new HealthCheck(GetType(), HealthCheckResult.Warning, "Radarr now supports Mono 5.x with btls enabled, consider removing MONO_TLS_PROVIDER=legacy option");
+ _logger.Debug()
+ .Message("Mono version {0} and legacy TLS provider is selected, recommending user to switch to btls.", monoVersion)
+ .WriteSentryDebug("LegacyTlsProvider", monoVersion.ToString())
+ .Write();
+
+ return new HealthCheck(GetType(), HealthCheckResult.Warning, "Sonarr Mono 4.x tls workaround still enabled, consider removing MONO_TLS_PROVIDER=legacy environment option");
}
return new HealthCheck(GetType());
diff --git a/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs
index faf2152d7..0bdc8466c 100644
--- a/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs
+++ b/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs
@@ -24,19 +24,47 @@ public override HealthCheck Check()
var monoVersion = _platformInfo.Version;
+ // Known buggy Mono versions
if (monoVersion == new Version("4.4.0") || monoVersion == new Version("4.4.1"))
{
_logger.Debug("Mono version {0}", monoVersion);
- return new HealthCheck(GetType(), HealthCheckResult.Error, $"Your Mono version {monoVersion} has a bug that causes issues connecting to indexers/download clients. You should upgrade to a higher version");
+ return new HealthCheck(GetType(), HealthCheckResult.Error,
+ $"Currently installed Mono version {monoVersion} has a bug that causes issues connecting to indexers/download clients. You should upgrade to a higher version",
+ "#currently-installed-mono-version-is-old-and-unsupported");
}
- if (monoVersion >= new Version("4.4.2"))
+ // Currently best stable Mono version (5.18 gets us .net 4.7.2 support)
+ var bestVersion = new Version("5.20");
+ var targetVersion = new Version("5.18");
+ if (monoVersion >= targetVersion)
{
- _logger.Debug("Mono version is 4.4.2 or better: {0}", monoVersion);
+ _logger.Debug("Mono version is {0} or better: {1}", targetVersion, monoVersion);
return new HealthCheck(GetType());
}
- return new HealthCheck(GetType(), HealthCheckResult.Warning, "You are running an old and unsupported version of Mono. Please upgrade Mono for improved stability.");
+ // Stable Mono versions
+ var stableVersion = new Version("5.16");
+ if (monoVersion >= stableVersion)
+ {
+ _logger.Debug("Mono version is {0} or better: {1}", stableVersion, monoVersion);
+ return new HealthCheck(GetType(), HealthCheckResult.Notice,
+ $"Currently installed Mono version {monoVersion} is supported but upgrading to {bestVersion} is recommended.",
+ "#currently-installed-mono-version-is-supported-but-upgrading-is-recommended");
+ }
+
+ // Old but supported Mono versions, there are known bugs
+ var supportedVersion = new Version("5.4");
+ if (monoVersion >= supportedVersion)
+ {
+ _logger.Debug("Mono version is {0} or better: {1}", supportedVersion, monoVersion);
+ return new HealthCheck(GetType(), HealthCheckResult.Warning,
+ $"Currently installed Mono version {monoVersion} is supported but has some known issues. Please upgrade Mono to version {bestVersion}.",
+ "#currently-installed-mono-version-is-supported-but-upgrading-is-recommended");
+ }
+
+ return new HealthCheck(GetType(), HealthCheckResult.Error,
+ $"Currently installed Mono version {monoVersion} is old and unsupported. Please upgrade Mono to version {bestVersion}.",
+ "#currently-installed-mono-version-is-old-and-unsupported");
}
public override bool CheckOnSchedule => false;
diff --git a/src/NzbDrone.Core/HealthCheck/HealthCheck.cs b/src/NzbDrone.Core/HealthCheck/HealthCheck.cs
index c02ead7a8..c410878be 100644
--- a/src/NzbDrone.Core/HealthCheck/HealthCheck.cs
+++ b/src/NzbDrone.Core/HealthCheck/HealthCheck.cs
@@ -46,7 +46,8 @@ private static HttpUri MakeWikiUrl(string fragment)
public enum HealthCheckResult
{
Ok = 0,
- Warning = 1,
- Error = 2
+ Notice = 1,
+ Warning = 2,
+ Error = 3
}
}
diff --git a/src/NzbDrone.Core/Indexers/Rarbg/RarbgRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Rarbg/RarbgRequestGenerator.cs
index 2df0b3825..79e750c28 100644
--- a/src/NzbDrone.Core/Indexers/Rarbg/RarbgRequestGenerator.cs
+++ b/src/NzbDrone.Core/Indexers/Rarbg/RarbgRequestGenerator.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using NzbDrone.Common.EnvironmentInfo;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
@@ -107,7 +108,7 @@ private IEnumerable GetMovieRequest(MovieSearchCriteria searchCr
requestBuilder.AddQueryParam("limit", "100");
requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings));
requestBuilder.AddQueryParam("format", "json_extended");
- requestBuilder.AddQueryParam("app_id", "Radarr");
+ requestBuilder.AddQueryParam("app_id", BuildInfo.AppName);
yield return new IndexerRequest(requestBuilder.Build());
}
diff --git a/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs b/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs
index a79ba682a..27a7a9143 100644
--- a/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs
+++ b/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs
@@ -2,7 +2,9 @@
using System.Linq;
using NLog;
using NLog.Config;
+using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
+using NzbDrone.Common.Instrumentation.Sentry;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Configuration.Events;
using NzbDrone.Core.Messaging.Events;
@@ -40,6 +42,9 @@ public void Reconfigure()
SetMinimumLogLevel(rules, "appFileDebug", minimumLogLevel <= LogLevel.Debug ? LogLevel.Debug : LogLevel.Off);
SetMinimumLogLevel(rules, "appFileTrace", minimumLogLevel <= LogLevel.Trace ? LogLevel.Trace : LogLevel.Off);
+ //Sentry
+ ReconfigureSentry();
+
LogManager.ReconfigExistingLoggers();
}
@@ -67,6 +72,16 @@ private void SetMinimumLogLevel(LoggingRule rule, LogLevel minimumLogLevel)
}
}
+ private void ReconfigureSentry()
+ {
+ var sentryTarget = LogManager.Configuration.AllTargets.OfType().FirstOrDefault();
+ if (sentryTarget != null)
+ {
+ sentryTarget.SentryEnabled = RuntimeInfo.IsProduction && _configFileProvider.AnalyticsEnabled || RuntimeInfo.IsDevelopment;
+ sentryTarget.FilterEvents = _configFileProvider.FilterSentryEvents;
+ }
+ }
+
private List GetLogLevels()
{
return new List
diff --git a/src/NzbDrone.Core/Instrumentation/ReconfigureSentry.cs b/src/NzbDrone.Core/Instrumentation/ReconfigureSentry.cs
new file mode 100644
index 000000000..034127e81
--- /dev/null
+++ b/src/NzbDrone.Core/Instrumentation/ReconfigureSentry.cs
@@ -0,0 +1,42 @@
+using System.Linq;
+using NLog;
+using NzbDrone.Common.EnvironmentInfo;
+using NzbDrone.Common.Instrumentation.Sentry;
+using NzbDrone.Core.Configuration;
+using NzbDrone.Core.Datastore;
+using NzbDrone.Core.Lifecycle;
+using NzbDrone.Core.Messaging.Events;
+
+namespace NzbDrone.Core.Instrumentation
+{
+ public class ReconfigureSentry : IHandleAsync
+ {
+ private readonly IConfigFileProvider _configFileProvider;
+ private readonly IPlatformInfo _platformInfo;
+ private readonly IMainDatabase _database;
+
+ public ReconfigureSentry(IConfigFileProvider configFileProvider,
+ IPlatformInfo platformInfo,
+ IMainDatabase database)
+ {
+ _configFileProvider = configFileProvider;
+ _platformInfo = platformInfo;
+ _database = database;
+ }
+
+ public void Reconfigure()
+ {
+ // Extended sentry config
+ var sentryTarget = LogManager.Configuration.AllTargets.OfType().FirstOrDefault();
+ if (sentryTarget != null)
+ {
+ sentryTarget.UpdateScope(_database.Version, _database.Migration, _configFileProvider.Branch, _platformInfo);
+ }
+ }
+
+ public void HandleAsync(ApplicationStartedEvent message)
+ {
+ Reconfigure();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs b/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs
index 8d26a883b..bf0e848f7 100644
--- a/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs
+++ b/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs
@@ -4,6 +4,7 @@
using NLog;
using RestSharp;
using NzbDrone.Core.Rest;
+using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Core.Notifications.Boxcar
{
@@ -75,7 +76,7 @@ private void SendNotification(string title, string message, RestRequest request,
request.AddParameter("user_credentials", settings.Token);
request.AddParameter("notification[title]", title);
request.AddParameter("notification[long_message]", message);
- request.AddParameter("notification[source_name]", "Radarr");
+ request.AddParameter("notification[source_name]", BuildInfo.AppName);
request.AddParameter("notification[icon_url]", "https://raw.githubusercontent.com/Radarr/Radarr/develop/Logo/64.png");
client.ExecuteAndValidate(request);
diff --git a/src/NzbDrone.Core/Notifications/Plex/PlexTv/PlexTvProxy.cs b/src/NzbDrone.Core/Notifications/Plex/PlexTv/PlexTvProxy.cs
index b13ef180b..c4fafe006 100644
--- a/src/NzbDrone.Core/Notifications/Plex/PlexTv/PlexTvProxy.cs
+++ b/src/NzbDrone.Core/Notifications/Plex/PlexTv/PlexTvProxy.cs
@@ -43,10 +43,10 @@ private HttpRequestBuilder BuildRequest(string clientIdentifier)
var requestBuilder = new HttpRequestBuilder("https://plex.tv")
.Accept(HttpAccept.Json)
.AddQueryParam("X-Plex-Client-Identifier", clientIdentifier)
- .AddQueryParam("X-Plex-Product", "Radarr")
+ .AddQueryParam("X-Plex-Product", BuildInfo.AppName)
.AddQueryParam("X-Plex-Platform", "Windows")
.AddQueryParam("X-Plex-Platform-Version", "7")
- .AddQueryParam("X-Plex-Device-Name", "Radarr")
+ .AddQueryParam("X-Plex-Device-Name", BuildInfo.AppName)
.AddQueryParam("X-Plex-Version", BuildInfo.Version.ToString());
return requestBuilder;
diff --git a/src/NzbDrone.Core/Notifications/Plex/PlexTv/PlexTvService.cs b/src/NzbDrone.Core/Notifications/Plex/PlexTv/PlexTvService.cs
index f9b96ca56..8866775c6 100644
--- a/src/NzbDrone.Core/Notifications/Plex/PlexTv/PlexTvService.cs
+++ b/src/NzbDrone.Core/Notifications/Plex/PlexTv/PlexTvService.cs
@@ -31,10 +31,10 @@ public PlexTvPinUrlResponse GetPinUrl()
var requestBuilder = new HttpRequestBuilder("https://plex.tv/api/v2/pins")
.Accept(HttpAccept.Json)
.AddQueryParam("X-Plex-Client-Identifier", clientIdentifier)
- .AddQueryParam("X-Plex-Product", "Radarr")
+ .AddQueryParam("X-Plex-Product", BuildInfo.AppName)
.AddQueryParam("X-Plex-Platform", "Windows")
.AddQueryParam("X-Plex-Platform-Version", "7")
- .AddQueryParam("X-Plex-Device-Name", "Radarr")
+ .AddQueryParam("X-Plex-Device-Name", BuildInfo.AppName)
.AddQueryParam("X-Plex-Version", BuildInfo.Version.ToString())
.AddQueryParam("strong", true);
@@ -57,7 +57,7 @@ public PlexTvSignInUrlResponse GetSignInUrl(string callbackUrl, int pinId, strin
.AddQueryParam("clientID", clientIdentifier)
.AddQueryParam("forwardUrl", callbackUrl)
.AddQueryParam("code", pinCode)
- .AddQueryParam("context[device][product]", "Radarr")
+ .AddQueryParam("context[device][product]", BuildInfo.AppName)
.AddQueryParam("context[device][platform]", "Windows")
.AddQueryParam("context[device][platformVersion]", "7")
.AddQueryParam("context[device][version]", BuildInfo.Version.ToString());
diff --git a/src/NzbDrone.Core/Notifications/Plex/Server/PlexServerProxy.cs b/src/NzbDrone.Core/Notifications/Plex/Server/PlexServerProxy.cs
index b4bee754d..8bf9cd59d 100644
--- a/src/NzbDrone.Core/Notifications/Plex/Server/PlexServerProxy.cs
+++ b/src/NzbDrone.Core/Notifications/Plex/Server/PlexServerProxy.cs
@@ -155,10 +155,10 @@ private HttpRequestBuilder BuildRequest(string resource, HttpMethod method, Plex
var requestBuilder = new HttpRequestBuilder($"{scheme}://{settings.Host}:{settings.Port}")
.Accept(HttpAccept.Json)
.AddQueryParam("X-Plex-Client-Identifier", _configService.PlexClientIdentifier)
- .AddQueryParam("X-Plex-Product", "Radarr")
+ .AddQueryParam("X-Plex-Product", BuildInfo.AppName)
.AddQueryParam("X-Plex-Platform", "Windows")
.AddQueryParam("X-Plex-Platform-Version", "7")
- .AddQueryParam("X-Plex-Device-Name", "Radarr")
+ .AddQueryParam("X-Plex-Device-Name", BuildInfo.AppName)
.AddQueryParam("X-Plex-Version", BuildInfo.Version.ToString());
if (settings.AuthToken.IsNotNullOrWhiteSpace())
diff --git a/src/NzbDrone.Core/Notifications/Prowl/ProwlService.cs b/src/NzbDrone.Core/Notifications/Prowl/ProwlService.cs
index e6897bb38..03a3d596b 100644
--- a/src/NzbDrone.Core/Notifications/Prowl/ProwlService.cs
+++ b/src/NzbDrone.Core/Notifications/Prowl/ProwlService.cs
@@ -1,6 +1,7 @@
using System;
using FluentValidation.Results;
using NLog;
+using NzbDrone.Common.EnvironmentInfo;
using Prowlin;
namespace NzbDrone.Core.Notifications.Prowl
@@ -26,7 +27,7 @@ public void SendNotification(string title, string message, string apiKey, Notifi
{
var notification = new Prowlin.Notification
{
- Application = "Radarr",
+ Application = BuildInfo.AppName,
Description = message,
Event = title,
Priority = priority,
diff --git a/src/NzbDrone.Core/Rest/RestClientFactory.cs b/src/NzbDrone.Core/Rest/RestClientFactory.cs
index 2cc3d15aa..99a3d1060 100644
--- a/src/NzbDrone.Core/Rest/RestClientFactory.cs
+++ b/src/NzbDrone.Core/Rest/RestClientFactory.cs
@@ -9,7 +9,7 @@ public static RestClient BuildClient(string baseUrl)
{
var restClient = new RestClient(baseUrl)
{
- UserAgent = $"Radarr/{BuildInfo.Version} ({OsInfo.Os})"
+ UserAgent = $"{BuildInfo.AppName}/{BuildInfo.Version} ({OsInfo.Os})"
};
diff --git a/src/NzbDrone.Core/Update/InstallUpdateService.cs b/src/NzbDrone.Core/Update/InstallUpdateService.cs
index 0fe04070e..a7d8e6684 100644
--- a/src/NzbDrone.Core/Update/InstallUpdateService.cs
+++ b/src/NzbDrone.Core/Update/InstallUpdateService.cs
@@ -32,6 +32,7 @@ public class InstallUpdateService : IExecute
private readonly IConfigFileProvider _configFileProvider;
private readonly IRuntimeInfo _runtimeInfo;
private readonly IBackupService _backupService;
+ private readonly IOsInfo _osInfo;
public InstallUpdateService(ICheckUpdateService checkUpdateService,
@@ -46,6 +47,7 @@ public InstallUpdateService(ICheckUpdateService checkUpdateService,
IConfigFileProvider configFileProvider,
IRuntimeInfo runtimeInfo,
IBackupService backupService,
+ IOsInfo osInfo,
Logger logger)
{
if (configFileProvider == null)
@@ -64,6 +66,7 @@ public InstallUpdateService(ICheckUpdateService checkUpdateService,
_configFileProvider = configFileProvider;
_runtimeInfo = runtimeInfo;
_backupService = backupService;
+ _osInfo = osInfo;
_logger = logger;
}
@@ -209,6 +212,11 @@ public void Execute(ApplicationUpdateCommand message)
return;
}
+ if (_osInfo.IsDocker)
+ {
+ throw new CommandFailedException("Updating is disabled inside a docker container. Please update the container image.");
+ }
+
if (OsInfo.IsNotWindows && !_configFileProvider.UpdateAutomatically && message.Trigger != CommandTrigger.Manual)
{
_logger.ProgressDebug("Auto-update not enabled, not installing available update.");
diff --git a/src/NzbDrone.Core/Update/UpdatePackageProvider.cs b/src/NzbDrone.Core/Update/UpdatePackageProvider.cs
index 84d0c5057..340b2056c 100644
--- a/src/NzbDrone.Core/Update/UpdatePackageProvider.cs
+++ b/src/NzbDrone.Core/Update/UpdatePackageProvider.cs
@@ -3,6 +3,7 @@
using NzbDrone.Common.Cloud;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http;
+using NzbDrone.Core.Analytics;
namespace NzbDrone.Core.Update
{
@@ -15,14 +16,16 @@ public interface IUpdatePackageProvider
public class UpdatePackageProvider : IUpdatePackageProvider
{
private readonly IHttpClient _httpClient;
- private readonly IPlatformInfo _platformInfo;
private readonly IHttpRequestBuilderFactory _requestBuilder;
+ private readonly IPlatformInfo _platformInfo;
+ private readonly IAnalyticsService _analyticsService;
- public UpdatePackageProvider(IHttpClient httpClient, IRadarrCloudRequestBuilder requestBuilder, IPlatformInfo platformInfo)
+ public UpdatePackageProvider(IHttpClient httpClient, IRadarrCloudRequestBuilder requestBuilder, IAnalyticsService analyticsService, IPlatformInfo platformInfo)
{
- _httpClient = httpClient;
_platformInfo = platformInfo;
+ _analyticsService = analyticsService;
_requestBuilder = requestBuilder.Services;
+ _httpClient = httpClient;
}
public UpdatePackage GetLatestUpdate(string branch, Version currentVersion)
@@ -32,10 +35,15 @@ public UpdatePackage GetLatestUpdate(string branch, Version currentVersion)
.AddQueryParam("version", currentVersion)
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
.AddQueryParam("runtimeVer", _platformInfo.Version)
- .SetSegment("branch", branch)
- .Build();
+ .SetSegment("branch", branch);
- var update = _httpClient.Get(request).Resource;
+ if (_analyticsService.IsEnabled)
+ {
+ // Send if the system is active so we know which versions to deprecate/ignore
+ request.AddQueryParam("active", _analyticsService.InstallIsActive.ToString().ToLower());
+ }
+
+ var update = _httpClient.Get(request.Build()).Resource;
if (!update.Available) return null;
@@ -49,12 +57,17 @@ public List GetRecentUpdates(string branch, Version currentVersio
.AddQueryParam("version", currentVersion)
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
.AddQueryParam("runtimeVer", _platformInfo.Version)
- .SetSegment("branch", branch)
- .Build();
+ .SetSegment("branch", branch);
- var updates = _httpClient.Get>(request);
+ if (_analyticsService.IsEnabled)
+ {
+ // Send if the system is active so we know which versions to deprecate/ignore
+ request.AddQueryParam("active", _analyticsService.InstallIsActive.ToString().ToLower());
+ }
+
+ var updates = _httpClient.Get>(request.Build());
return updates.Resource;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Host.Test/RouterTest.cs b/src/NzbDrone.Host.Test/RouterTest.cs
index c7a07b6fc..b44807fdb 100644
--- a/src/NzbDrone.Host.Test/RouterTest.cs
+++ b/src/NzbDrone.Host.Test/RouterTest.cs
@@ -29,7 +29,6 @@ public void Route_should_call_install_service_when_application_mode_is_install()
Mocker.GetMock()
.Setup(c => c.SpawnNewProcess("sc.exe", It.IsAny(), null, true));
-
Mocker.GetMock().SetupGet(c => c.IsUserInteractive).Returns(true);
Subject.Route(ApplicationModes.InstallService);
diff --git a/src/NzbDrone.Host/AccessControl/RemoteAccessAdapter.cs b/src/NzbDrone.Host/AccessControl/RemoteAccessAdapter.cs
new file mode 100644
index 000000000..f9bbd6ac5
--- /dev/null
+++ b/src/NzbDrone.Host/AccessControl/RemoteAccessAdapter.cs
@@ -0,0 +1,46 @@
+using NzbDrone.Common.EnvironmentInfo;
+
+namespace Radarr.Host.AccessControl
+{
+ public interface IRemoteAccessAdapter
+ {
+ void MakeAccessible(bool passive);
+ }
+
+ public class RemoteAccessAdapter : IRemoteAccessAdapter
+ {
+ private readonly IRuntimeInfo _runtimeInfo;
+ private readonly IUrlAclAdapter _urlAclAdapter;
+ private readonly IFirewallAdapter _firewallAdapter;
+ private readonly ISslAdapter _sslAdapter;
+
+ public RemoteAccessAdapter(IRuntimeInfo runtimeInfo,
+ IUrlAclAdapter urlAclAdapter,
+ IFirewallAdapter firewallAdapter,
+ ISslAdapter sslAdapter)
+ {
+ _runtimeInfo = runtimeInfo;
+ _urlAclAdapter = urlAclAdapter;
+ _firewallAdapter = firewallAdapter;
+ _sslAdapter = sslAdapter;
+ }
+
+ public void MakeAccessible(bool passive)
+ {
+ if (OsInfo.IsWindows)
+ {
+ if (_runtimeInfo.IsAdmin)
+ {
+ _firewallAdapter.MakeAccessible();
+ _sslAdapter.Register();
+ }
+ else if (!passive)
+ {
+ throw new RemoteAccessException("Failed to register URLs for Radarr. Radarr will not be accessible remotely");
+ }
+ }
+
+ _urlAclAdapter.ConfigureUrls();
+ }
+ }
+}
diff --git a/src/NzbDrone.Host/AccessControl/RemoteAccessException.cs b/src/NzbDrone.Host/AccessControl/RemoteAccessException.cs
new file mode 100644
index 000000000..be7917f90
--- /dev/null
+++ b/src/NzbDrone.Host/AccessControl/RemoteAccessException.cs
@@ -0,0 +1,24 @@
+using System;
+using NzbDrone.Common.Exceptions;
+
+namespace Radarr.Host.AccessControl
+{
+ public class RemoteAccessException : NzbDroneException
+ {
+ public RemoteAccessException(string message, params object[] args) : base(message, args)
+ {
+ }
+
+ public RemoteAccessException(string message) : base(message)
+ {
+ }
+
+ public RemoteAccessException(string message, Exception innerException, params object[] args) : base(message, innerException, args)
+ {
+ }
+
+ public RemoteAccessException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/src/NzbDrone.Host/ApplicationModes.cs b/src/NzbDrone.Host/ApplicationModes.cs
index 3495d8688..196aecde6 100644
--- a/src/NzbDrone.Host/ApplicationModes.cs
+++ b/src/NzbDrone.Host/ApplicationModes.cs
@@ -7,5 +7,6 @@ public enum ApplicationModes
InstallService,
UninstallService,
Service,
+ RegisterUrl
}
}
diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs
index c29f7c36f..4c00d2e75 100644
--- a/src/NzbDrone.Host/Bootstrap.cs
+++ b/src/NzbDrone.Host/Bootstrap.cs
@@ -29,6 +29,7 @@ public static void Start(StartupContext startupContext, IUserAlert userAlert, Ac
}
_container = MainAppContainerBuilder.BuildContainer(startupContext);
+ _container.Resolve().Initialize();
_container.Resolve().Register();
_container.Resolve().Write();
@@ -109,11 +110,17 @@ private static void EnsureSingleInstance(bool isService, IStartupContext startup
private static ApplicationModes GetApplicationMode(IStartupContext startupContext)
{
- if (startupContext.Flags.Contains(StartupContext.HELP))
+ if (startupContext.Help)
{
return ApplicationModes.Help;
}
+ if (OsInfo.IsWindows && startupContext.RegisterUrl)
+ {
+ return ApplicationModes.RegisterUrl;
+ }
+
+
if (OsInfo.IsWindows && startupContext.InstallService)
{
return ApplicationModes.InstallService;
@@ -138,6 +145,7 @@ private static bool IsInUtilityMode(ApplicationModes applicationMode)
{
case ApplicationModes.InstallService:
case ApplicationModes.UninstallService:
+ case ApplicationModes.RegisterUrl:
case ApplicationModes.Help:
{
return true;
diff --git a/src/NzbDrone.Host/MainAppContainerBuilder.cs b/src/NzbDrone.Host/MainAppContainerBuilder.cs
index 3bbc0cc52..5dab4fb81 100644
--- a/src/NzbDrone.Host/MainAppContainerBuilder.cs
+++ b/src/NzbDrone.Host/MainAppContainerBuilder.cs
@@ -31,7 +31,6 @@ private MainAppContainerBuilder(StartupContext args, List assemblies)
AutoRegisterImplementations();
Container.Register();
- Container.Register();
}
}
}
diff --git a/src/NzbDrone.Host/Owin/OwinHostController.cs b/src/NzbDrone.Host/Owin/OwinHostController.cs
index a2000974b..5beb8c4c8 100644
--- a/src/NzbDrone.Host/Owin/OwinHostController.cs
+++ b/src/NzbDrone.Host/Owin/OwinHostController.cs
@@ -8,41 +8,26 @@ namespace Radarr.Host.Owin
public class OwinHostController : IHostController
{
private readonly IOwinAppFactory _owinAppFactory;
- private readonly IRuntimeInfo _runtimeInfo;
+ private readonly IRemoteAccessAdapter _removeAccessAdapter;
private readonly IUrlAclAdapter _urlAclAdapter;
- private readonly IFirewallAdapter _firewallAdapter;
- private readonly ISslAdapter _sslAdapter;
private readonly Logger _logger;
private IDisposable _owinApp;
public OwinHostController(
IOwinAppFactory owinAppFactory,
- IRuntimeInfo runtimeInfo,
+ IRemoteAccessAdapter removeAccessAdapter,
IUrlAclAdapter urlAclAdapter,
- IFirewallAdapter firewallAdapter,
- ISslAdapter sslAdapter,
Logger logger)
{
_owinAppFactory = owinAppFactory;
- _runtimeInfo = runtimeInfo;
+ _removeAccessAdapter = removeAccessAdapter;
_urlAclAdapter = urlAclAdapter;
- _firewallAdapter = firewallAdapter;
- _sslAdapter = sslAdapter;
_logger = logger;
}
public void StartServer()
{
- if (OsInfo.IsWindows)
- {
- if (_runtimeInfo.IsAdmin)
- {
- _firewallAdapter.MakeAccessible();
- _sslAdapter.Register();
- }
- }
-
- _urlAclAdapter.ConfigureUrls();
+ _removeAccessAdapter.MakeAccessible(true);
_logger.Info("Listening on the following URLs:");
foreach (var url in _urlAclAdapter.Urls)
@@ -53,7 +38,6 @@ public void StartServer()
_owinApp = _owinAppFactory.CreateApp(_urlAclAdapter.Urls);
}
-
public void StopServer()
{
if (_owinApp == null) return;
@@ -63,8 +47,5 @@ public void StopServer()
_owinApp = null;
_logger.Info("Host has stopped");
}
-
-
-
}
}
\ No newline at end of file
diff --git a/src/NzbDrone.Host/Owin/OwinServiceProvider.cs b/src/NzbDrone.Host/Owin/OwinServiceProvider.cs
index 80d3e9a83..29baa908e 100644
--- a/src/NzbDrone.Host/Owin/OwinServiceProvider.cs
+++ b/src/NzbDrone.Host/Owin/OwinServiceProvider.cs
@@ -11,6 +11,7 @@
using NzbDrone.Core.Configuration;
using Radarr.Host.Owin.MiddleWare;
using Owin;
+using NzbDrone.Common.EnvironmentInfo;
namespace Radarr.Host.Owin
{
@@ -70,7 +71,7 @@ public IDisposable CreateApp(List urls)
private void BuildApp(IAppBuilder appBuilder)
{
- appBuilder.Properties["host.AppName"] = "NzbDrone";
+ appBuilder.Properties["host.AppName"] = BuildInfo.AppName;
foreach (var middleWare in _owinMiddleWares.OrderBy(c => c.Order))
{
diff --git a/src/NzbDrone.Host/Router.cs b/src/NzbDrone.Host/Router.cs
index e617fb50d..98f0057d1 100644
--- a/src/NzbDrone.Host/Router.cs
+++ b/src/NzbDrone.Host/Router.cs
@@ -1,6 +1,11 @@
+using System;
using NLog;
using NzbDrone.Common;
using NzbDrone.Common.EnvironmentInfo;
+using NzbDrone.Common.Processes;
+using Radarr.Host.AccessControl;
+using IServiceProvider = NzbDrone.Common.IServiceProvider;
+
namespace Radarr.Host
{
@@ -10,15 +15,24 @@ public class Router
private readonly IServiceProvider _serviceProvider;
private readonly IConsoleService _consoleService;
private readonly IRuntimeInfo _runtimeInfo;
+ private readonly IProcessProvider _processProvider;
+ private readonly IRemoteAccessAdapter _remoteAccessAdapter;
private readonly Logger _logger;
- public Router(INzbDroneServiceFactory nzbDroneServiceFactory, IServiceProvider serviceProvider,
- IConsoleService consoleService, IRuntimeInfo runtimeInfo, Logger logger)
+ public Router(INzbDroneServiceFactory nzbDroneServiceFactory,
+ IServiceProvider serviceProvider,
+ IConsoleService consoleService,
+ IRuntimeInfo runtimeInfo,
+ IProcessProvider processProvider,
+ IRemoteAccessAdapter remoteAccessAdapter,
+ Logger logger)
{
_nzbDroneServiceFactory = nzbDroneServiceFactory;
_serviceProvider = serviceProvider;
_consoleService = consoleService;
_runtimeInfo = runtimeInfo;
+ _processProvider = processProvider;
+ _remoteAccessAdapter = remoteAccessAdapter;
_logger = logger;
}
@@ -50,8 +64,13 @@ public void Route(ApplicationModes applicationModes)
}
else
{
+ _remoteAccessAdapter.MakeAccessible(true);
_serviceProvider.Install(ServiceProvider.SERVICE_NAME);
- _serviceProvider.Start(ServiceProvider.SERVICE_NAME);
+ _serviceProvider.SetPermissions(ServiceProvider.SERVICE_NAME);
+
+ // Start the service and exit.
+ // Ensures that there isn't an instance of Radarr already running that the service account cannot stop.
+ _processProvider.SpawnNewProcess("sc.exe", $"start {ServiceProvider.SERVICE_NAME}", null, true);
}
break;
}
@@ -67,6 +86,13 @@ public void Route(ApplicationModes applicationModes)
_serviceProvider.Uninstall(ServiceProvider.SERVICE_NAME);
}
+ break;
+ }
+ case ApplicationModes.RegisterUrl:
+ {
+ _logger.Debug("Regiser URL selected");
+ _remoteAccessAdapter.MakeAccessible(false);
+
break;
}
default:
@@ -76,7 +102,5 @@ public void Route(ApplicationModes applicationModes)
}
}
}
-
-
}
-}
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Integration.Test/ApiTests/BlacklistFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/BlacklistFixture.cs
index b20d7b886..7443b8cf1 100644
--- a/src/NzbDrone.Integration.Test/ApiTests/BlacklistFixture.cs
+++ b/src/NzbDrone.Integration.Test/ApiTests/BlacklistFixture.cs
@@ -1,6 +1,6 @@
using FluentAssertions;
using NUnit.Framework;
-using NzbDrone.Api.Movies;
+using Radarr.Api.V2.Movies;
namespace NzbDrone.Integration.Test.ApiTests
{
@@ -15,7 +15,7 @@ public void should_be_able_to_add_to_blacklist()
{
_movie = EnsureMovie(11, "The Blacklist");
- Blacklist.Post(new Api.Blacklist.BlacklistResource
+ Blacklist.Post(new Radarr.Api.V2.Blacklist.BlacklistResource
{
MovieId = _movie.Id,
SourceTitle = "Blacklist.S01E01.Brought.To.You.By-BoomBoxHD"
diff --git a/src/NzbDrone.Integration.Test/ApiTests/CalendarFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/CalendarFixture.cs
index cc2a13619..2d66accf7 100644
--- a/src/NzbDrone.Integration.Test/ApiTests/CalendarFixture.cs
+++ b/src/NzbDrone.Integration.Test/ApiTests/CalendarFixture.cs
@@ -1,6 +1,6 @@
using FluentAssertions;
using NUnit.Framework;
-using NzbDrone.Api.Movies;
+using Radarr.Api.V2.Movies;
using NzbDrone.Integration.Test.Client;
using System;
using System.Collections.Generic;
diff --git a/src/NzbDrone.Integration.Test/ApiTests/CommandFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/CommandFixture.cs
index 2c3da675c..719d1c7ac 100644
--- a/src/NzbDrone.Integration.Test/ApiTests/CommandFixture.cs
+++ b/src/NzbDrone.Integration.Test/ApiTests/CommandFixture.cs
@@ -1,6 +1,6 @@
using FluentAssertions;
using NUnit.Framework;
-using NzbDrone.Api.Commands;
+using NzbDrone.Integration.Test.Client;
namespace NzbDrone.Integration.Test.ApiTests
{
@@ -10,7 +10,7 @@ public class CommandFixture : IntegrationTest
[Test]
public void should_be_able_to_run_rss_sync()
{
- var response = Commands.Post(new CommandResource { Name = "rsssync" });
+ var response = Commands.Post(new SimpleCommandResource { Name = "rsssync" });
response.Id.Should().NotBe(0);
}
diff --git a/src/NzbDrone.Integration.Test/ApiTests/DiskSpaceFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/DiskSpaceFixture.cs
index 527f18346..e43e0859e 100644
--- a/src/NzbDrone.Integration.Test/ApiTests/DiskSpaceFixture.cs
+++ b/src/NzbDrone.Integration.Test/ApiTests/DiskSpaceFixture.cs
@@ -1,7 +1,7 @@
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
-using NzbDrone.Api.DiskSpace;
+using Radarr.Api.V2.DiskSpace;
using NzbDrone.Integration.Test.Client;
namespace NzbDrone.Integration.Test.ApiTests
diff --git a/src/NzbDrone.Integration.Test/ApiTests/DownloadClientFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/DownloadClientFixture.cs
index 5032fd3c6..a95d44641 100644
--- a/src/NzbDrone.Integration.Test/ApiTests/DownloadClientFixture.cs
+++ b/src/NzbDrone.Integration.Test/ApiTests/DownloadClientFixture.cs
@@ -16,8 +16,8 @@ public void add_downloadclient_without_name_should_return_badrequest()
var schema = DownloadClients.Schema().First(v => v.Implementation == "UsenetBlackhole");
schema.Enable = true;
- schema.Fields.First(v => v.Name == "WatchFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Watch");
- schema.Fields.First(v => v.Name == "NzbFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Nzb");
+ schema.Fields.First(v => v.Name == "watchFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Watch");
+ schema.Fields.First(v => v.Name == "nzbFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Nzb");
DownloadClients.InvalidPost(schema);
}
@@ -31,7 +31,7 @@ public void add_downloadclient_without_nzbfolder_should_return_badrequest()
schema.Enable = true;
schema.Name = "Test UsenetBlackhole";
- schema.Fields.First(v => v.Name == "WatchFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Watch");
+ schema.Fields.First(v => v.Name == "watchFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Watch");
DownloadClients.InvalidPost(schema);
}
@@ -45,7 +45,7 @@ public void add_downloadclient_without_watchfolder_should_return_badrequest()
schema.Enable = true;
schema.Name = "Test UsenetBlackhole";
- schema.Fields.First(v => v.Name == "NzbFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Nzb");
+ schema.Fields.First(v => v.Name == "nzbFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Nzb");
DownloadClients.InvalidPost(schema);
}
@@ -59,8 +59,8 @@ public void add_downloadclient()
schema.Enable = true;
schema.Name = "Test UsenetBlackhole";
- schema.Fields.First(v => v.Name == "WatchFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Watch");
- schema.Fields.First(v => v.Name == "NzbFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Nzb");
+ schema.Fields.First(v => v.Name == "watchFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Watch");
+ schema.Fields.First(v => v.Name == "nzbFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Nzb");
var result = DownloadClients.Post(schema);
@@ -99,7 +99,7 @@ public void update_downloadclient()
EnsureNoDownloadClient();
var client = EnsureDownloadClient();
- client.Fields.First(v => v.Name == "NzbFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Nzb2");
+ client.Fields.First(v => v.Name == "nzbFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Nzb2");
var result = DownloadClients.Put(client);
result.Should().NotBeNull();
diff --git a/src/NzbDrone.Integration.Test/ApiTests/MovieEditorFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/MovieEditorFixture.cs
index f46553294..a90932aaf 100644
--- a/src/NzbDrone.Integration.Test/ApiTests/MovieEditorFixture.cs
+++ b/src/NzbDrone.Integration.Test/ApiTests/MovieEditorFixture.cs
@@ -1,6 +1,7 @@
using FluentAssertions;
using NUnit.Framework;
using System.Linq;
+using Radarr.Api.V2.Movies;
using NzbDrone.Test.Common;
namespace NzbDrone.Integration.Test.ApiTests
@@ -10,11 +11,11 @@ public class MovieEditorFixture : IntegrationTest
{
private void GivenExistingMovie()
{
- foreach (var title in new[] { "90210", "Dexter" })
+ foreach (var title in new[] { "The Dark Knight", "Pulp Fiction" })
{
var newMovie = Movies.Lookup(title).First();
- newMovie.ProfileId = 1;
+ newMovie.QualityProfileId = 1;
newMovie.Path = string.Format(@"C:\Test\{0}", title).AsOsAgnostic();
Movies.Post(newMovie);
@@ -26,17 +27,18 @@ public void should_be_able_to_update_multiple_movies()
{
GivenExistingMovie();
- var movie = Movies.All();
+ var movies = Movies.All();
- foreach (var s in movie)
+ var movieEditor = new MovieEditorResource
{
- s.ProfileId = 2;
- }
+ QualityProfileId = 2,
+ MovieIds = movies.Select(o => o.Id).ToList()
+ };
- var result = Movies.Editor(movie);
+ var result = Movies.Editor(movieEditor);
result.Should().HaveCount(2);
- result.TrueForAll(s => s.ProfileId == 2).Should().BeTrue();
+ result.TrueForAll(s => s.QualityProfileId == 2).Should().BeTrue();
}
}
}
diff --git a/src/NzbDrone.Integration.Test/ApiTests/MovieFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/MovieFixture.cs
index 3b6343ac8..e0a632c18 100644
--- a/src/NzbDrone.Integration.Test/ApiTests/MovieFixture.cs
+++ b/src/NzbDrone.Integration.Test/ApiTests/MovieFixture.cs
@@ -18,7 +18,7 @@ public void add_movie_with_tags_should_store_them()
var movie = Movies.Lookup("imdb:tt0110912").Single();
- movie.ProfileId = 1;
+ movie.QualityProfileId = 1;
movie.Path = Path.Combine(MovieRootFolder, movie.Title);
movie.Tags = new HashSet();
movie.Tags.Add(tag.Id);
@@ -48,7 +48,7 @@ public void add_movie_without_path_should_return_badrequest()
var movie = Movies.Lookup("imdb:tt0110912").Single();
- movie.ProfileId = 1;
+ movie.QualityProfileId = 1;
Movies.InvalidPost(movie);
}
@@ -60,14 +60,14 @@ public void add_movie()
var movie = Movies.Lookup("imdb:tt0110912").Single();
- movie.ProfileId = 1;
+ movie.QualityProfileId = 1;
movie.Path = Path.Combine(MovieRootFolder, movie.Title);
var result = Movies.Post(movie);
result.Should().NotBeNull();
result.Id.Should().NotBe(0);
- result.ProfileId.Should().Be(1);
+ result.QualityProfileId.Should().Be(1);
result.Path.Should().Be(Path.Combine(MovieRootFolder, movie.Title));
}
@@ -105,16 +105,16 @@ public void update_movie_profile_id()
var movie = EnsureMovie(680, "Pulp Fiction");
var profileId = 1;
- if (movie.ProfileId == profileId)
+ if (movie.QualityProfileId == profileId)
{
profileId = 2;
}
- movie.ProfileId = profileId;
+ movie.QualityProfileId = profileId;
var result = Movies.Put(movie);
- Movies.Get(movie.Id).ProfileId.Should().Be(profileId);
+ Movies.Get(movie.Id).QualityProfileId.Should().Be(profileId);
}
[Test, Order(3)]
diff --git a/src/NzbDrone.Integration.Test/ApiTests/NamingConfigFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/NamingConfigFixture.cs
index c203e6576..df59cc90d 100644
--- a/src/NzbDrone.Integration.Test/ApiTests/NamingConfigFixture.cs
+++ b/src/NzbDrone.Integration.Test/ApiTests/NamingConfigFixture.cs
@@ -25,11 +25,11 @@ public void should_be_able_to_get_by_id()
public void should_be_able_to_update()
{
var config = NamingConfig.GetSingle();
- config.RenameEpisodes = false;
+ config.RenameMovies = false;
config.StandardMovieFormat = "{Movie Title}";
var result = NamingConfig.Put(config);
- result.RenameEpisodes.Should().BeFalse();
+ result.RenameMovies.Should().BeFalse();
result.StandardMovieFormat.Should().Be(config.StandardMovieFormat);
}
@@ -38,7 +38,7 @@ public void should_be_able_to_update()
public void should_get_bad_request_if_standard_format_is_empty()
{
var config = NamingConfig.GetSingle();
- config.RenameEpisodes = true;
+ config.RenameMovies = true;
config.StandardMovieFormat = "";
var errors = NamingConfig.InvalidPut(config);
@@ -49,7 +49,7 @@ public void should_get_bad_request_if_standard_format_is_empty()
public void should_get_bad_request_if_standard_format_doesnt_contain_title()
{
var config = NamingConfig.GetSingle();
- config.RenameEpisodes = true;
+ config.RenameMovies = true;
config.StandardMovieFormat = "{quality}";
var errors = NamingConfig.InvalidPut(config);
@@ -60,7 +60,7 @@ public void should_get_bad_request_if_standard_format_doesnt_contain_title()
public void should_not_require_format_when_rename_episodes_is_false()
{
var config = NamingConfig.GetSingle();
- config.RenameEpisodes = false;
+ config.RenameMovies = false;
config.StandardMovieFormat = "";
var errors = NamingConfig.InvalidPut(config);
@@ -71,7 +71,7 @@ public void should_not_require_format_when_rename_episodes_is_false()
public void should_require_format_when_rename_episodes_is_true()
{
var config = NamingConfig.GetSingle();
- config.RenameEpisodes = true;
+ config.RenameMovies = true;
config.StandardMovieFormat = "";
var errors = NamingConfig.InvalidPut(config);
@@ -82,7 +82,7 @@ public void should_require_format_when_rename_episodes_is_true()
public void should_get_bad_request_if_movie_folder_format_does_not_contain_movie_title()
{
var config = NamingConfig.GetSingle();
- config.RenameEpisodes = true;
+ config.RenameMovies = true;
config.MovieFolderFormat = "This and That";
var errors = NamingConfig.InvalidPut(config);
diff --git a/src/NzbDrone.Integration.Test/ApiTests/NotificationFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/NotificationFixture.cs
index c5ebfa8ef..d5abc9930 100644
--- a/src/NzbDrone.Integration.Test/ApiTests/NotificationFixture.cs
+++ b/src/NzbDrone.Integration.Test/ApiTests/NotificationFixture.cs
@@ -34,7 +34,7 @@ public void should_be_able_to_add_a_new_notification()
var xbmc = schema.Single(s => s.Implementation.Equals("Xbmc", StringComparison.InvariantCultureIgnoreCase));
xbmc.Name = "Test XBMC";
- xbmc.Fields.Single(f => f.Name.Equals("Host")).Value = "localhost";
+ xbmc.Fields.Single(f => f.Name.Equals("host")).Value = "localhost";
var result = Notifications.Post(xbmc);
Notifications.Delete(result.Id);
diff --git a/src/NzbDrone.Integration.Test/ApiTests/ReleaseFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/ReleaseFixture.cs
index cfad5038e..151d7f3d1 100644
--- a/src/NzbDrone.Integration.Test/ApiTests/ReleaseFixture.cs
+++ b/src/NzbDrone.Integration.Test/ApiTests/ReleaseFixture.cs
@@ -1,6 +1,6 @@
using FluentAssertions;
using NUnit.Framework;
-using NzbDrone.Api.Indexers;
+using Radarr.Api.V2.Indexers;
using System.Linq;
using System.Net;
diff --git a/src/NzbDrone.Integration.Test/ApiTests/RootFolderFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/RootFolderFixture.cs
index 5133a5da7..c8332e4cb 100644
--- a/src/NzbDrone.Integration.Test/ApiTests/RootFolderFixture.cs
+++ b/src/NzbDrone.Integration.Test/ApiTests/RootFolderFixture.cs
@@ -1,7 +1,7 @@
using System;
using FluentAssertions;
using NUnit.Framework;
-using NzbDrone.Api.RootFolders;
+using Radarr.Api.V2.RootFolders;
namespace NzbDrone.Integration.Test.ApiTests
{
diff --git a/src/NzbDrone.Integration.Test/ApiTests/WantedTests/CutoffUnmetFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/WantedTests/CutoffUnmetFixture.cs
deleted file mode 100644
index 5b3c0a06f..000000000
--- a/src/NzbDrone.Integration.Test/ApiTests/WantedTests/CutoffUnmetFixture.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-using System.Linq;
-using FluentAssertions;
-using NUnit.Framework;
-using NzbDrone.Core.Qualities;
-
-namespace NzbDrone.Integration.Test.ApiTests.WantedTests
-{
- [TestFixture]
- public class CutoffUnmetFixture : IntegrationTest
- {
- [Test, Order(1)]
- public void cutoff_should_have_monitored_items()
- {
- EnsureProfileCutoff(1, Quality.HDTV720p);
- var movie = EnsureMovie(680, "Pulp Fiction", true);
- EnsureMovieFile(movie, Quality.SDTV);
-
- var result = WantedCutoffUnmet.GetPaged(0, 15, "physicalRelease", "desc", "monitored", "true");
-
- result.Records.Should().NotBeEmpty();
- }
-
- [Test, Order(1)]
- public void cutoff_should_not_have_unmonitored_items()
- {
- EnsureProfileCutoff(1, Quality.HDTV720p);
- var movie = EnsureMovie(680, "Pulp Fiction", false);
- EnsureMovieFile(movie, Quality.SDTV);
-
- var result = WantedCutoffUnmet.GetPaged(0, 15, "physicalRelease", "desc", "monitored", "true");
-
- result.Records.Should().BeEmpty();
- }
-
- [Test, Order(1)]
- public void cutoff_should_not_have_released_items()
- {
- EnsureProfileCutoff(1, Quality.HDTV720p);
- var movie = EnsureMovie(680, "Pulp Fiction", true);
- EnsureMovieFile(movie, Quality.SDTV);
-
- var result = WantedCutoffUnmet.GetPaged(0, 15, "physicalRelease", "desc", "status", "inCinemas");
-
- result.Records.Should().BeEmpty();
- }
-
- [Test, Order(1)]
- public void cutoff_should_have_movie()
- {
- EnsureProfileCutoff(1, Quality.HDTV720p);
- var movie = EnsureMovie(680, "Pulp Fiction", true);
- EnsureMovieFile(movie, Quality.SDTV);
-
- var result = WantedCutoffUnmet.GetPaged(0, 15, "physicalRelease", "desc");
-
- result.Records.First().Title.Should().Be("Pulp Fiction");
- }
-
- [Test, Order(2)]
- public void cutoff_should_have_unmonitored_items()
- {
- EnsureProfileCutoff(1, Quality.HDTV720p);
- var movie = EnsureMovie(680, "Pulp Fiction", false);
- EnsureMovieFile(movie, Quality.SDTV);
-
- var result = WantedCutoffUnmet.GetPaged(0, 15, "physicalRelease", "desc", "monitored", "false");
-
- result.Records.Should().NotBeEmpty();
- }
-
- [Test, Order(2)]
- public void cutoff_should_have_released_items()
- {
- EnsureProfileCutoff(1, Quality.HDTV720p);
- var movie = EnsureMovie(680, "Pulp Fiction", false);
- EnsureMovieFile(movie, Quality.SDTV);
-
- var result = WantedCutoffUnmet.GetPaged(0, 15, "physicalRelease", "desc", "status", "released");
-
- result.Records.Should().NotBeEmpty();
- }
- }
-}
\ No newline at end of file
diff --git a/src/NzbDrone.Integration.Test/ApiTests/WantedTests/MissingFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/WantedTests/MissingFixture.cs
deleted file mode 100644
index 62e594381..000000000
--- a/src/NzbDrone.Integration.Test/ApiTests/WantedTests/MissingFixture.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using System.Linq;
-using FluentAssertions;
-using NUnit.Framework;
-using NzbDrone.Core.Qualities;
-
-namespace NzbDrone.Integration.Test.ApiTests.WantedTests
-{
- [TestFixture]
- public class MissingFixture : IntegrationTest
- {
- [Test, Order(0)]
- public void missing_should_be_empty()
- {
- EnsureNoMovie(680, "Pulp Fiction");
-
- var result = WantedMissing.GetPaged(0, 15, "physicalRelease", "desc");
-
- result.Records.Should().BeEmpty();
- }
-
- [Test, Order(1)]
- public void missing_should_have_monitored_items()
- {
- EnsureMovie(680, "Pulp Fiction", true);
-
- var result = WantedMissing.GetPaged(0, 15, "physicalRelease", "desc", "monitored", "true");
-
- result.Records.Should().NotBeEmpty();
- }
-
- [Test, Order(1)]
- public void missing_should_have_movie()
- {
- EnsureMovie(680, "Pulp Fiction", true);
-
- var result = WantedMissing.GetPaged(0, 15, "physicalRelease", "desc");
-
- result.Records.First().Title.Should().Be("Pulp Fiction");
- }
-
- [Test, Order(1)]
- public void missing_should_not_have_unmonitored_items()
- {
- EnsureMovie(680, "Pulp Fiction", false);
-
- var result = WantedMissing.GetPaged(0, 15, "physicalRelease", "desc", "monitored", "true");
-
- result.Records.Should().BeEmpty();
- }
-
- [Test, Order(1)]
- public void missing_should_not_have_released_items()
- {
- EnsureMovie(680, "Pulp Fiction", false);
-
- var result = WantedMissing.GetPaged(0, 15, "physicalRelease", "desc", "status", "inCinemas");
-
- result.Records.Should().BeEmpty();
- }
-
- [Test, Order(2)]
- public void missing_should_have_unmonitored_items()
- {
- EnsureMovie(680, "Pulp Fiction", false);
-
- var result = WantedMissing.GetPaged(0, 15, "physicalRelease", "desc", "monitored", "false");
-
- result.Records.Should().NotBeEmpty();
- }
-
- [Test, Order(2)]
- public void missing_should_have_released_items()
- {
- EnsureMovie(680, "Pulp Fiction", false);
-
- var result = WantedMissing.GetPaged(0, 15, "physicalRelease", "desc", "status", "released");
-
- result.Records.Should().NotBeEmpty();
- }
- }
-}
\ No newline at end of file
diff --git a/src/NzbDrone.Integration.Test/Client/ClientBase.cs b/src/NzbDrone.Integration.Test/Client/ClientBase.cs
index 28c7a1d7a..3811ae1c8 100644
--- a/src/NzbDrone.Integration.Test/Client/ClientBase.cs
+++ b/src/NzbDrone.Integration.Test/Client/ClientBase.cs
@@ -2,7 +2,6 @@
using System.Net;
using FluentAssertions;
using NLog;
-using NzbDrone.Api;
using Radarr.Http.REST;
using Radarr.Http;
using NzbDrone.Common.Serializer;
@@ -40,7 +39,7 @@ public RestRequest BuildRequest(string command = "")
return request;
}
- public T Execute(IRestRequest request, HttpStatusCode statusCode) where T : class, new()
+ public string Execute(IRestRequest request, HttpStatusCode statusCode)
{
_logger.Info("{0}: {1}", request.Method, _restClient.BuildUri(request));
@@ -58,7 +57,14 @@ public RestRequest BuildRequest(string command = "")
response.StatusCode.Should().Be(statusCode);
- return Json.Deserialize(response.Content);
+ return response.Content;
+ }
+
+ public T Execute(IRestRequest request, HttpStatusCode statusCode) where T : class, new()
+ {
+ var content = Execute(request, statusCode);
+
+ return Json.Deserialize(content);
}
private static void AssertDisableCache(IList headers)
diff --git a/src/NzbDrone.Integration.Test/Client/CommandClient.cs b/src/NzbDrone.Integration.Test/Client/CommandClient.cs
index 047427a98..59becc84d 100644
--- a/src/NzbDrone.Integration.Test/Client/CommandClient.cs
+++ b/src/NzbDrone.Integration.Test/Client/CommandClient.cs
@@ -1,23 +1,47 @@
-using NzbDrone.Api.Commands;
-using RestSharp;
+using RestSharp;
using NzbDrone.Core.Messaging.Commands;
using FluentAssertions;
using System.Threading;
using NUnit.Framework;
using System.Linq;
+using System;
+using Radarr.Http.REST;
+using Newtonsoft.Json;
namespace NzbDrone.Integration.Test.Client
{
- public class CommandClient : ClientBase
+ public class SimpleCommandResource : RestResource
+ {
+ public string Name { get; set; }
+ public string CommandName { get; set; }
+ public string Message { get; set; }
+ public CommandPriority Priority { get; set; }
+ public CommandStatus Status { get; set; }
+ public DateTime Queued { get; set; }
+ public DateTime? Started { get; set; }
+ public DateTime? Ended { get; set; }
+ public TimeSpan? Duration { get; set; }
+ public string Exception { get; set; }
+ public CommandTrigger Trigger { get; set; }
+
+ [JsonIgnore]
+ public Command Body { get; set; }
+ [JsonProperty("body")]
+ public Command BodyReadOnly { get { return Body; } }
+ }
+
+ public class CommandClient : ClientBase
{
public CommandClient(IRestClient restClient, string apiKey)
- : base(restClient, apiKey)
+ : base(restClient, apiKey, "command")
{
}
- public CommandResource PostAndWait(CommandResource command)
+ public SimpleCommandResource PostAndWait(T command) where T : Command, new()
{
- var result = Post(command);
+ var request = BuildRequest();
+ request.AddBody(command);
+ var result = Post(request);
result.Id.Should().NotBe(0);
for (var i = 0; i < 50; i++)
diff --git a/src/NzbDrone.Integration.Test/Client/DownloadClientClient.cs b/src/NzbDrone.Integration.Test/Client/DownloadClientClient.cs
index e31e38748..74797e56d 100644
--- a/src/NzbDrone.Integration.Test/Client/DownloadClientClient.cs
+++ b/src/NzbDrone.Integration.Test/Client/DownloadClientClient.cs
@@ -1,5 +1,5 @@
using System.Collections.Generic;
-using NzbDrone.Api.DownloadClient;
+using Radarr.Api.V2.DownloadClient;
using RestSharp;
namespace NzbDrone.Integration.Test.Client
diff --git a/src/NzbDrone.Integration.Test/Client/IndexerClient.cs b/src/NzbDrone.Integration.Test/Client/IndexerClient.cs
index 9d6f9b974..cf231b1b9 100644
--- a/src/NzbDrone.Integration.Test/Client/IndexerClient.cs
+++ b/src/NzbDrone.Integration.Test/Client/IndexerClient.cs
@@ -1,4 +1,4 @@
-using NzbDrone.Api.Indexers;
+using Radarr.Api.V2.Indexers;
using RestSharp;
namespace NzbDrone.Integration.Test.Client
diff --git a/src/NzbDrone.Integration.Test/Client/LogsClient.cs b/src/NzbDrone.Integration.Test/Client/LogsClient.cs
new file mode 100644
index 000000000..b64ec2971
--- /dev/null
+++ b/src/NzbDrone.Integration.Test/Client/LogsClient.cs
@@ -0,0 +1,24 @@
+using System;
+using RestSharp;
+
+namespace NzbDrone.Integration.Test.Client
+{
+ public class LogsClient : ClientBase
+ {
+ public LogsClient(IRestClient restClient, string apiKey)
+ : base(restClient, apiKey, "log/file")
+ {
+ }
+
+ public string[] GetLogFileLines(string filename)
+ {
+ var request = BuildRequest(filename);
+ var content = Execute(request, System.Net.HttpStatusCode.OK);
+
+ var lines = content.Split('\n');
+ lines = Array.ConvertAll(lines, s => s.TrimEnd('\r'));
+ Array.Resize(ref lines, lines.Length - 1);
+ return lines;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Integration.Test/Client/MovieClient.cs b/src/NzbDrone.Integration.Test/Client/MovieClient.cs
index 38fe8c325..1a57f045a 100644
--- a/src/NzbDrone.Integration.Test/Client/MovieClient.cs
+++ b/src/NzbDrone.Integration.Test/Client/MovieClient.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
using System.Net;
-using NzbDrone.Api.Movies;
+using Radarr.Api.V2.Movies;
using RestSharp;
namespace NzbDrone.Integration.Test.Client
@@ -19,7 +19,7 @@ public List Lookup(string term)
return Get>(request);
}
- public List Editor(List movie)
+ public List Editor(MovieEditorResource movie)
{
var request = BuildRequest("editor");
request.AddJsonBody(movie);
diff --git a/src/NzbDrone.Integration.Test/Client/NotificationClient.cs b/src/NzbDrone.Integration.Test/Client/NotificationClient.cs
index 6f0f06eb5..e3c0790eb 100644
--- a/src/NzbDrone.Integration.Test/Client/NotificationClient.cs
+++ b/src/NzbDrone.Integration.Test/Client/NotificationClient.cs
@@ -1,5 +1,5 @@
using System.Collections.Generic;
-using NzbDrone.Api.Notifications;
+using Radarr.Api.V2.Notifications;
using RestSharp;
namespace NzbDrone.Integration.Test.Client
diff --git a/src/NzbDrone.Integration.Test/Client/ReleaseClient.cs b/src/NzbDrone.Integration.Test/Client/ReleaseClient.cs
index 46a6db839..6b189961f 100644
--- a/src/NzbDrone.Integration.Test/Client/ReleaseClient.cs
+++ b/src/NzbDrone.Integration.Test/Client/ReleaseClient.cs
@@ -1,4 +1,4 @@
-using NzbDrone.Api.Indexers;
+using Radarr.Api.V2.Indexers;
using RestSharp;
namespace NzbDrone.Integration.Test.Client
diff --git a/src/NzbDrone.Integration.Test/HttpLogFixture.cs b/src/NzbDrone.Integration.Test/HttpLogFixture.cs
index be474ad0a..ba2d4cf35 100644
--- a/src/NzbDrone.Integration.Test/HttpLogFixture.cs
+++ b/src/NzbDrone.Integration.Test/HttpLogFixture.cs
@@ -1,8 +1,7 @@
-using System.IO;
+using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
-using NzbDrone.Api.Movies;
namespace NzbDrone.Integration.Test
{
@@ -18,16 +17,18 @@ public void should_log_on_error()
var resultGet = Movies.All();
- var logFile = Path.Combine(_runner.AppData, "logs", "radarr.trace.txt");
- var logLines = File.ReadAllLines(logFile);
+ var logFile = "radarr.trace.txt";
+ var logLines = Logs.GetLogFileLines(logFile);
- var resultPost = Movies.InvalidPost(new MovieResource());
+ var resultPost = Movies.InvalidPost(new Radarr.Api.V2.Movies.MovieResource());
- logLines = File.ReadAllLines(logFile).Skip(logLines.Length).ToArray();
+ // Skip 2 and 1 to ignore the logs endpoint
+ logLines = Logs.GetLogFileLines(logFile).Skip(logLines.Length + 2).ToArray();
+ Array.Resize(ref logLines, logLines.Length - 1);
- logLines.Should().Contain(v => v.Contains("|Trace|Http|Req"));
- logLines.Should().Contain(v => v.Contains("|Trace|Http|Res"));
- logLines.Should().Contain(v => v.Contains("|Debug|Api|"));
+ logLines.Should().Contain(v => v.Contains("|Trace|Http|Req") && v.Contains("/api/v2/movie/"));
+ logLines.Should().Contain(v => v.Contains("|Trace|Http|Res") && v.Contains("/api/v2/movie/: 400.BadRequest"));
+ logLines.Should().Contain(v => v.Contains("|Debug|Api|") && v.Contains("/api/v2/movie/: 400.BadRequest"));
}
}
-}
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Integration.Test/IntegrationTest.cs b/src/NzbDrone.Integration.Test/IntegrationTest.cs
index 2e6020ac8..a23b22676 100644
--- a/src/NzbDrone.Integration.Test/IntegrationTest.cs
+++ b/src/NzbDrone.Integration.Test/IntegrationTest.cs
@@ -26,10 +26,11 @@ protected override void StartTestTarget()
protected override void InitializeTestTarget()
{
- Indexers.Post(new Api.Indexers.IndexerResource
+ Indexers.Post(new Radarr.Api.V2.Indexers.IndexerResource
{
EnableRss = false,
- EnableSearch = false,
+ EnableInteractiveSearch = false,
+ EnableAutomaticSearch = false,
ConfigContract = nameof(NewznabSettings),
Implementation = nameof(Newznab),
Name = "NewznabTest",
diff --git a/src/NzbDrone.Integration.Test/IntegrationTestBase.cs b/src/NzbDrone.Integration.Test/IntegrationTestBase.cs
index e51bed674..389327c59 100644
--- a/src/NzbDrone.Integration.Test/IntegrationTestBase.cs
+++ b/src/NzbDrone.Integration.Test/IntegrationTestBase.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
@@ -10,16 +11,16 @@
using NLog.Config;
using NLog.Targets;
using NUnit.Framework;
-using NzbDrone.Api.Blacklist;
-using NzbDrone.Api.Commands;
-using NzbDrone.Api.Config;
-using NzbDrone.Api.DownloadClient;
-using NzbDrone.Api.MovieFiles;
-using NzbDrone.Api.History;
-using NzbDrone.Api.Profiles;
-using NzbDrone.Api.RootFolders;
-using NzbDrone.Api.Movies;
-using NzbDrone.Api.Tags;
+using Radarr.Api.V2.Blacklist;
+using Radarr.Api.V2.Commands;
+using Radarr.Api.V2.Config;
+using Radarr.Api.V2.DownloadClient;
+using Radarr.Api.V2.MovieFiles;
+using Radarr.Api.V2.History;
+using Radarr.Api.V2.Profiles.Quality;
+using Radarr.Api.V2.RootFolders;
+using Radarr.Api.V2.Movies;
+using Radarr.Api.V2.Tags;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.MediaFiles.Events;
@@ -43,9 +44,10 @@ public abstract class IntegrationTestBase
public ClientBase History;
public ClientBase HostConfig;
public IndexerClient Indexers;
+ public LogsClient Logs;
public ClientBase NamingConfig;
public NotificationClient Notifications;
- public ClientBase Profiles;
+ public ClientBase Profiles;
public ReleaseClient Releases;
public ClientBase RootFolders;
public MovieClient Movies;
@@ -63,11 +65,9 @@ public IntegrationTestBase()
new StartupContext();
LogManager.Configuration = new LoggingConfiguration();
- var consoleTarget = new ConsoleTarget { Layout = "${level}: ${message} ${exception}", DetectConsoleAvailable = true};
+ var consoleTarget = new ConsoleTarget { Layout = "${level}: ${message} ${exception}" };
LogManager.Configuration.AddTarget(consoleTarget.GetType().Name, consoleTarget);
LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, consoleTarget));
-
- LogManager.ReconfigExistingLoggers();
}
public string TempDirectory { get; private set; }
@@ -94,7 +94,7 @@ public void SmokeTestSetup()
protected virtual void InitRestClients()
{
- RestClient = new RestClient(RootUrl + "api/");
+ RestClient = new RestClient(RootUrl + "api/v2/");
RestClient.AddDefaultHeader("Authentication", ApiKey);
RestClient.AddDefaultHeader("X-Api-Key", ApiKey);
@@ -104,9 +104,10 @@ protected virtual void InitRestClients()
History = new ClientBase(RestClient, ApiKey);
HostConfig = new ClientBase(RestClient, ApiKey, "config/host");
Indexers = new IndexerClient(RestClient, ApiKey);
+ Logs = new LogsClient(RestClient, ApiKey);
NamingConfig = new ClientBase(RestClient, ApiKey, "config/naming");
Notifications = new NotificationClient(RestClient, ApiKey);
- Profiles = new ClientBase(RestClient, ApiKey);
+ Profiles = new ClientBase(RestClient, ApiKey);
Releases = new ReleaseClient(RestClient, ApiKey);
RootFolders = new ClientBase(RestClient, ApiKey);
Movies = new MovieClient(RestClient, ApiKey);
@@ -124,7 +125,7 @@ public void SmokeTestTearDown()
[SetUp]
public void IntegrationSetUp()
{
- TempDirectory = Path.Combine(TestContext.CurrentContext.TestDirectory, "_test_" + DateTime.UtcNow.Ticks);
+ TempDirectory = Path.Combine(TestContext.CurrentContext.TestDirectory, "_test_" + Process.GetCurrentProcess().Id + "_" + DateTime.UtcNow.Ticks);
// Wait for things to get quiet, otherwise the previous test might influence the current one.
Commands.WaitAll();
@@ -148,6 +149,17 @@ public void IntegrationTearDown()
_signalrConnection = null;
_signalRReceived = new List();
}
+
+ if (Directory.Exists(TempDirectory))
+ {
+ try
+ {
+ Directory.Delete(TempDirectory, true);
+ }
+ catch
+ {
+ }
+ }
}
public string GetTempDirectory(params string[] args)
@@ -213,7 +225,7 @@ public MovieResource EnsureMovie(int tmdbid, string movieTitle, bool? monitored
{
var lookup = Movies.Lookup("tmdb:" + tmdbid);
var movie = lookup.First();
- movie.ProfileId = 1;
+ movie.QualityProfileId = 1;
movie.Path = Path.Combine(MovieRootFolder, movie.Title);
movie.Monitored = true;
movie.AddOptions = new Core.Movies.AddMovieOptions();
@@ -268,7 +280,7 @@ public MovieFileResource EnsureMovieFile(MovieResource movie, Quality quality)
//File.Copy(sourcePath, path);
File.WriteAllText(path, "Fake Movie");
- Commands.PostAndWait(new CommandResource { Name = "refreshmovie", Body = new RefreshMovieCommand(movie.Id) });
+ Commands.PostAndWait(new RefreshMovieCommand(movie.Id));
Commands.WaitAll();
result = Movies.Get(movie.Id);
@@ -279,13 +291,13 @@ public MovieFileResource EnsureMovieFile(MovieResource movie, Quality quality)
return result.MovieFile;
}
- public ProfileResource EnsureProfileCutoff(int profileId, Quality cutoff)
+ public QualityProfileResource EnsureProfileCutoff(int profileId, Quality cutoff)
{
var profile = Profiles.Get(profileId);
- if (profile.Cutoff != cutoff)
+ if (profile.Cutoff != cutoff.Id)
{
- profile.Cutoff = cutoff;
+ profile.Cutoff = cutoff.Id;
profile = Profiles.Put(profile);
}
@@ -324,8 +336,8 @@ public DownloadClientResource EnsureDownloadClient(bool enabled = true)
schema.Enable = enabled;
schema.Name = "Test UsenetBlackhole";
- schema.Fields.First(v => v.Name == "WatchFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Watch");
- schema.Fields.First(v => v.Name == "NzbFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Nzb");
+ schema.Fields.First(v => v.Name == "watchFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Watch");
+ schema.Fields.First(v => v.Name == "nzbFolder").Value = GetTempDirectory("Download", "UsenetBlackhole", "Nzb");
client = DownloadClients.Post(schema);
}
diff --git a/src/NzbDrone.Integration.Test/Radarr.Integration.Test.csproj b/src/NzbDrone.Integration.Test/Radarr.Integration.Test.csproj
index c8e920721..9b760c349 100644
--- a/src/NzbDrone.Integration.Test/Radarr.Integration.Test.csproj
+++ b/src/NzbDrone.Integration.Test/Radarr.Integration.Test.csproj
@@ -7,7 +7,7 @@
-
+
\ No newline at end of file
diff --git a/src/NzbDrone.Mono.Test/EnvironmentInfo/MonoPlatformInfoFixture.cs b/src/NzbDrone.Mono.Test/EnvironmentInfo/MonoPlatformInfoFixture.cs
index a1bcfd1cd..80fce9cc1 100644
--- a/src/NzbDrone.Mono.Test/EnvironmentInfo/MonoPlatformInfoFixture.cs
+++ b/src/NzbDrone.Mono.Test/EnvironmentInfo/MonoPlatformInfoFixture.cs
@@ -13,7 +13,7 @@ public class MonoPlatformInfoFixture : TestBase
[Test]
public void should_get_framework_version()
{
- Subject.Version.Major.Should().BeOneOf(4, 5);
+ Subject.Version.Major.Should().BeOneOf(4, 5, 6);
if (Subject.Version.Major == 4)
{
Subject.Version.Minor.Should().BeOneOf(0, 5, 6);
diff --git a/src/NzbDrone.Mono.Test/EnvironmentInfo/ReleaseFileVersionAdapterFixture.cs b/src/NzbDrone.Mono.Test/EnvironmentInfo/ReleaseFileVersionAdapterFixture.cs
index f13c58bba..c4b477c5e 100644
--- a/src/NzbDrone.Mono.Test/EnvironmentInfo/ReleaseFileVersionAdapterFixture.cs
+++ b/src/NzbDrone.Mono.Test/EnvironmentInfo/ReleaseFileVersionAdapterFixture.cs
@@ -8,7 +8,7 @@
namespace NzbDrone.Mono.Test.EnvironmentInfo
{
[TestFixture]
- [Platform("Mono")]
+ [Platform("Linux")]
public class ReleaseFileVersionAdapterFixture : TestBase
{
[SetUp]
diff --git a/src/NzbDrone.Mono.Test/EnvironmentInfo/VersionAdapters/ReleaseFileVersionAdapterFixture.cs b/src/NzbDrone.Mono.Test/EnvironmentInfo/VersionAdapters/ReleaseFileVersionAdapterFixture.cs
index 4f1bee23f..a6937868e 100644
--- a/src/NzbDrone.Mono.Test/EnvironmentInfo/VersionAdapters/ReleaseFileVersionAdapterFixture.cs
+++ b/src/NzbDrone.Mono.Test/EnvironmentInfo/VersionAdapters/ReleaseFileVersionAdapterFixture.cs
@@ -15,7 +15,7 @@ public class ReleaseFileVersionAdapterFixture : TestBase(Mocker.Resolve());
diff --git a/src/NzbDrone.Mono/EnvironmentInfo/MonoPlatformInfo.cs b/src/NzbDrone.Mono/EnvironmentInfo/MonoPlatformInfo.cs
index 0676b69cc..ca487eedd 100644
--- a/src/NzbDrone.Mono/EnvironmentInfo/MonoPlatformInfo.cs
+++ b/src/NzbDrone.Mono/EnvironmentInfo/MonoPlatformInfo.cs
@@ -30,7 +30,6 @@ public MonoPlatformInfo(Logger logger)
if (versionMatch.Success)
{
runTimeVersion = new Version(versionMatch.Groups["version"].Value);
- Environment.SetEnvironmentVariable("RUNTIME_VERSION", runTimeVersion.ToString());
}
}
}
diff --git a/src/NzbDrone.Test.Common/ExceptionVerification.cs b/src/NzbDrone.Test.Common/ExceptionVerification.cs
index b86220f7c..a60d1297b 100644
--- a/src/NzbDrone.Test.Common/ExceptionVerification.cs
+++ b/src/NzbDrone.Test.Common/ExceptionVerification.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
using NLog;
using NLog.Targets;
using NUnit.Framework;
@@ -11,17 +12,27 @@ public class ExceptionVerification : Target
{
private static List _logs = new List();
+ private static ManualResetEventSlim _waitEvent = new ManualResetEventSlim();
+
protected override void Write(LogEventInfo logEvent)
{
- if (logEvent.Level >= LogLevel.Warn)
+ lock (_logs)
{
- _logs.Add(logEvent);
+ if (logEvent.Level >= LogLevel.Warn)
+ {
+ _logs.Add(logEvent);
+ _waitEvent.Set();
+ }
}
}
public static void Reset()
{
- _logs = new List();
+ lock (_logs)
+ {
+ _logs.Clear();
+ _waitEvent.Reset();
+ }
}
public static void AssertNoUnexpectedLogs()
@@ -47,6 +58,29 @@ private static string GetLogsString(IEnumerable logs)
return errors;
}
+ public static void WaitForErrors(int count, int msec)
+ {
+ while (true)
+ {
+ lock (_logs)
+ {
+ var levelLogs = _logs.Where(l => l.Level == LogLevel.Error).ToList();
+
+ if (levelLogs.Count >= count)
+ {
+ break;
+ }
+
+ _waitEvent.Reset();
+ }
+
+ if (!_waitEvent.Wait(msec))
+ break;
+ }
+
+ Expected(LogLevel.Error, count);
+ }
+
public static void ExpectedErrors(int count)
{
Expected(LogLevel.Error, count);
@@ -74,50 +108,62 @@ public static void IgnoreErrors()
public static void MarkInconclusive(Type exception)
{
- var inconclusiveLogs = _logs.Where(l => l.Exception != null && l.Exception.GetType() == exception).ToList();
-
- if (inconclusiveLogs.Any())
+ lock (_logs)
{
- inconclusiveLogs.ForEach(c => _logs.Remove(c));
- Assert.Inconclusive(GetLogsString(inconclusiveLogs));
+ var inconclusiveLogs = _logs.Where(l => l.Exception != null && l.Exception.GetType() == exception).ToList();
+
+ if (inconclusiveLogs.Any())
+ {
+ inconclusiveLogs.ForEach(c => _logs.Remove(c));
+ Assert.Inconclusive(GetLogsString(inconclusiveLogs));
+ }
}
}
public static void MarkInconclusive(string text)
{
- var inconclusiveLogs = _logs.Where(l => l.FormattedMessage.ToLower().Contains(text.ToLower())).ToList();
-
- if (inconclusiveLogs.Any())
+ lock (_logs)
{
- inconclusiveLogs.ForEach(c => _logs.Remove(c));
- Assert.Inconclusive(GetLogsString(inconclusiveLogs));
+ var inconclusiveLogs = _logs.Where(l => l.FormattedMessage.ToLower().Contains(text.ToLower())).ToList();
+
+ if (inconclusiveLogs.Any())
+ {
+ inconclusiveLogs.ForEach(c => _logs.Remove(c));
+ Assert.Inconclusive(GetLogsString(inconclusiveLogs));
+ }
}
}
private static void Expected(LogLevel level, int count)
{
- var levelLogs = _logs.Where(l => l.Level == level).ToList();
-
- if (levelLogs.Count != count)
+ lock (_logs)
{
+ var levelLogs = _logs.Where(l => l.Level == level).ToList();
- var message = string.Format("{0} {1}(s) were expected but {2} were logged.\n\r{3}",
- count, level, levelLogs.Count, GetLogsString(levelLogs));
+ if (levelLogs.Count != count)
+ {
- message = "\n\r****************************************************************************************\n\r"
- + message +
- "\n\r****************************************************************************************";
+ var message = string.Format("{0} {1}(s) were expected but {2} were logged.\n\r{3}",
+ count, level, levelLogs.Count, GetLogsString(levelLogs));
- Assert.Fail(message);
+ message = "\n\r****************************************************************************************\n\r"
+ + message +
+ "\n\r****************************************************************************************";
+
+ Assert.Fail(message);
+ }
+
+ levelLogs.ForEach(c => _logs.Remove(c));
}
-
- levelLogs.ForEach(c => _logs.Remove(c));
}
private static void Ignore(LogLevel level)
{
- var levelLogs = _logs.Where(l => l.Level == level).ToList();
- levelLogs.ForEach(c => _logs.Remove(c));
+ lock (_logs)
+ {
+ var levelLogs = _logs.Where(l => l.Level == level).ToList();
+ levelLogs.ForEach(c => _logs.Remove(c));
+ }
}
}
}
\ No newline at end of file
diff --git a/src/NzbDrone.Test.Common/LoggingTest.cs b/src/NzbDrone.Test.Common/LoggingTest.cs
index b8aba6dcd..3b673390b 100644
--- a/src/NzbDrone.Test.Common/LoggingTest.cs
+++ b/src/NzbDrone.Test.Common/LoggingTest.cs
@@ -1,6 +1,8 @@
using NLog;
using NLog.Config;
using NLog.Targets;
+using System;
+using System.IO;
using NUnit.Framework;
using NUnit.Framework.Interfaces;
using NzbDrone.Common.EnvironmentInfo;
@@ -20,9 +22,19 @@ protected static void InitLogging()
if (LogManager.Configuration == null || LogManager.Configuration.AllTargets.None(c => c is ExceptionVerification))
{
LogManager.Configuration = new LoggingConfiguration();
- var consoleTarget = new ConsoleTarget { Layout = "${level}: ${message} ${exception}" };
- LogManager.Configuration.AddTarget(consoleTarget.GetType().Name, consoleTarget);
- LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, consoleTarget));
+
+ var logOutput = TestLogOutput.Console;
+ Enum.TryParse(Environment.GetEnvironmentVariable("RADARR_TESTS_LOG_OUTPUT"), out logOutput);
+
+ switch (logOutput)
+ {
+ case TestLogOutput.Console:
+ RegisterConsoleLogger();
+ break;
+ case TestLogOutput.File:
+ RegisterFileLogger();
+ break;
+ }
RegisterExceptionVerification();
@@ -30,6 +42,32 @@ protected static void InitLogging()
}
}
+ private static void RegisterConsoleLogger()
+ {
+ var consoleTarget = new ConsoleTarget { Layout = "${level}: ${message} ${exception}" };
+ LogManager.Configuration.AddTarget(consoleTarget.GetType().Name, consoleTarget);
+ LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, consoleTarget));
+ }
+
+ private static void RegisterFileLogger()
+ {
+ const string layout = @"${level}|${message}${onexception:inner=${newline}${newline}${exception:format=ToString}${newline}}";
+
+ var fileTarget = new FileTarget();
+
+ fileTarget.Name = "Test File Logger";
+ fileTarget.FileName = Path.Combine(TestContext.CurrentContext.WorkDirectory, "TestLog.txt");
+ fileTarget.AutoFlush = false;
+ fileTarget.KeepFileOpen = true;
+ fileTarget.ConcurrentWrites = true;
+ fileTarget.ConcurrentWriteAttemptDelay = 50;
+ fileTarget.ConcurrentWriteAttempts = 10;
+ fileTarget.Layout = layout;
+
+ LogManager.Configuration.AddTarget(fileTarget.GetType().Name, fileTarget);
+ LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, fileTarget));
+ }
+
private static void RegisterExceptionVerification()
{
var exceptionVerification = new ExceptionVerification();
@@ -42,6 +80,7 @@ public void LoggingTestSetup()
{
InitLogging();
ExceptionVerification.Reset();
+ TestLogger.Info("--- Start: {0} ---", TestContext.CurrentContext.Test.FullName);
}
[TearDown]
@@ -53,6 +92,8 @@ public void LoggingDownBase()
{
ExceptionVerification.AssertNoUnexpectedLogs();
}
+
+ TestLogger.Info("--- End: {0} ---", TestContext.CurrentContext.Test.FullName);
}
}
}
diff --git a/src/NzbDrone.Test.Common/NzbDroneRunner.cs b/src/NzbDrone.Test.Common/NzbDroneRunner.cs
index 1e89f8636..da8b9bc9b 100644
--- a/src/NzbDrone.Test.Common/NzbDroneRunner.cs
+++ b/src/NzbDrone.Test.Common/NzbDroneRunner.cs
@@ -9,6 +9,7 @@
using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Processes;
+using NzbDrone.Core.Configuration;
using RestSharp;
namespace NzbDrone.Test.Common
@@ -30,7 +31,10 @@ public NzbDroneRunner(Logger logger, int port = 7878)
public void Start()
{
- AppData = Path.Combine(TestContext.CurrentContext.TestDirectory, "_intg_" + DateTime.Now.Ticks);
+ AppData = Path.Combine(TestContext.CurrentContext.TestDirectory, "_intg_" + TestBase.GetUID());
+ Directory.CreateDirectory(AppData);
+
+ GenerateConfigFile();
var radarrConsoleExe = OsInfo.IsWindows ? "Radarr.Console.exe" : "Radarr.exe";
@@ -40,7 +44,7 @@ public void Start()
}
else
{
- Start(Path.Combine(TestContext.CurrentContext.TestDirectory, "bin", radarrConsoleExe));
+ Start(Path.Combine("bin", radarrConsoleExe));
}
while (true)
@@ -52,8 +56,6 @@ public void Start()
Assert.Fail("Process has exited");
}
- SetApiKey();
-
var request = new RestRequest("system/status");
request.AddHeader("Authorization", ApiKey);
request.AddHeader("X-Api-Key", ApiKey);
@@ -74,13 +76,22 @@ public void Start()
public void KillAll()
{
- if (_nzbDroneProcess != null)
+ try
{
- _processProvider.Kill(_nzbDroneProcess.Id);
+ if (_nzbDroneProcess != null)
+ {
+ _processProvider.Kill(_nzbDroneProcess.Id);
+ }
+
+ _processProvider.KillAll(ProcessProvider.RADARR_CONSOLE_PROCESS_NAME);
+ _processProvider.KillAll(ProcessProvider.RADARR_PROCESS_NAME);
+ }
+ catch (InvalidOperationException)
+ {
+ // May happen if the process closes while being closed
}
- _processProvider.KillAll(ProcessProvider.RADARR_CONSOLE_PROCESS_NAME);
- _processProvider.KillAll(ProcessProvider.RADARR_PROCESS_NAME);
+ TestBase.DeleteTempFolder(AppData);
}
private void Start(string outputRadarrConsoleExe)
@@ -100,33 +111,26 @@ private void OnOutputDataReceived(string data)
}
}
- private void SetApiKey()
+ private void GenerateConfigFile()
{
var configFile = Path.Combine(AppData, "config.xml");
- var attempts = 0;
- while (ApiKey == null && attempts < 50)
- {
- try
- {
- if (File.Exists(configFile))
- {
- var apiKeyElement = XDocument.Load(configFile)
- .XPathSelectElement("Config/ApiKey");
- if (apiKeyElement != null)
- {
- ApiKey = apiKeyElement.Value;
- }
- }
- }
- catch (XmlException ex)
- {
- Console.WriteLine("Error getting API Key from XML file: " + ex.Message, ex);
- }
+ // Generate and set the api key so we don't have to poll the config file
+ var apiKey = Guid.NewGuid().ToString().Replace("-", "");
- attempts++;
- Thread.Sleep(1000);
- }
+ var xDoc = new XDocument(
+ new XDeclaration("1.0", "utf-8", "yes"),
+ new XElement(ConfigFileProvider.CONFIG_ELEMENT_NAME,
+ new XElement(nameof(ConfigFileProvider.ApiKey), apiKey),
+ new XElement(nameof(ConfigFileProvider.AnalyticsEnabled), false)
+ )
+ );
+
+ var data = xDoc.ToString();
+
+ File.WriteAllText(configFile, data);
+
+ ApiKey = apiKey;
}
}
}
diff --git a/src/NzbDrone.Test.Common/TestBase.cs b/src/NzbDrone.Test.Common/TestBase.cs
index 14310f7f3..3ea76b4d8 100644
--- a/src/NzbDrone.Test.Common/TestBase.cs
+++ b/src/NzbDrone.Test.Common/TestBase.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using System.IO;
using System.Threading;
using FluentAssertions;
@@ -45,6 +46,7 @@ public abstract class TestBase : LoggingTest
{
private static readonly Random _random = new Random();
+ private static int _nextUid;
private AutoMoqer _mocker;
protected AutoMoqer Mocker
@@ -84,7 +86,21 @@ private string VirtualPath
}
}
- protected string TempFolder { get; private set; }
+ private string _tempFolder;
+ protected string TempFolder
+ {
+ get
+ {
+ if (_tempFolder == null)
+ {
+ _tempFolder = Path.Combine(TestContext.CurrentContext.TestDirectory, "_temp_" + GetUID());
+
+ Directory.CreateDirectory(_tempFolder);
+ }
+
+ return _tempFolder;
+ }
+ }
[SetUp]
public void TestBaseSetup()
@@ -93,9 +109,7 @@ public void TestBaseSetup()
LogManager.ReconfigExistingLoggers();
- TempFolder = Path.Combine(TestContext.CurrentContext.TestDirectory, "_temp_" + DateTime.Now.Ticks);
-
- Directory.CreateDirectory(TempFolder);
+ _tempFolder = null;
}
[TearDown]
@@ -103,9 +117,26 @@ public void TestBaseTearDown()
{
_mocker = null;
+ DeleteTempFolder(_tempFolder);
+ }
+
+
+ public static string GetUID()
+ {
+ return Process.GetCurrentProcess().Id + "_" + DateTime.Now.Ticks + "_" + Interlocked.Increment(ref _nextUid);
+ }
+
+ public static void DeleteTempFolder(string folder)
+ {
+ if (folder == null)
+ {
+ return;
+ }
+
+
try
{
- var tempFolder = new DirectoryInfo(TempFolder);
+ var tempFolder = new DirectoryInfo(folder);
if (tempFolder.Exists)
{
foreach (var file in tempFolder.GetFiles("*", SearchOption.AllDirectories))
diff --git a/src/NzbDrone.Test.Common/TestLogOutput.cs b/src/NzbDrone.Test.Common/TestLogOutput.cs
new file mode 100644
index 000000000..91cf2d52d
--- /dev/null
+++ b/src/NzbDrone.Test.Common/TestLogOutput.cs
@@ -0,0 +1,9 @@
+namespace NzbDrone.Test.Common
+{
+ public enum TestLogOutput
+ {
+ Console = 0,
+ File = 1,
+ None = 2
+ }
+}
diff --git a/src/NzbDrone.Update.Test/StartNzbDroneService.cs b/src/NzbDrone.Update.Test/StartNzbDroneService.cs
index ddfeb14e1..789cfc864 100644
--- a/src/NzbDrone.Update.Test/StartNzbDroneService.cs
+++ b/src/NzbDrone.Update.Test/StartNzbDroneService.cs
@@ -16,7 +16,7 @@ public class StartNzbDroneServiceFixture : TestBase
[Test]
public void should_start_service_if_app_type_was_serivce()
{
- const string targetFolder = "c:\\Radarr\\";
+ string targetFolder = "c:\\Radarr\\".AsOsAgnostic();
Subject.Start(AppType.Service, targetFolder);
@@ -26,13 +26,14 @@ public void should_start_service_if_app_type_was_serivce()
[Test]
public void should_start_console_if_app_type_was_service_but_start_failed_because_of_permissions()
{
- const string targetFolder = "c:\\Radarr\\";
+ string targetFolder = "c:\\Radarr\\".AsOsAgnostic();
+ string targetProcess = "c:\\Radarr\\Radarr.Console.exe".AsOsAgnostic();
Mocker.GetMock().Setup(c => c.Start(ServiceProvider.SERVICE_NAME)).Throws(new InvalidOperationException());
Subject.Start(AppType.Service, targetFolder);
- Mocker.GetMock().Verify(c => c.SpawnNewProcess("c:\\Radarr\\Radarr.Console.exe", "/" + StartupContext.NO_BROWSER, null, false), Times.Once());
+ Mocker.GetMock().Verify(c => c.SpawnNewProcess(targetProcess, "/" + StartupContext.NO_BROWSER, null, false), Times.Once());
ExceptionVerification.ExpectedWarns(1);
}
diff --git a/src/NzbDrone.Update/UpdateApp.cs b/src/NzbDrone.Update/UpdateApp.cs
index 9bfd4d1b0..3e91d4977 100644
--- a/src/NzbDrone.Update/UpdateApp.cs
+++ b/src/NzbDrone.Update/UpdateApp.cs
@@ -35,7 +35,7 @@ public static void Main(string[] args)
Logger.Info("Starting Radarr Update Client");
_container = UpdateContainerBuilder.Build(startupArgument);
-
+ _container.Resolve().Initialize();
_container.Resolve().Start(args);
Logger.Info("Update completed successfully");
diff --git a/src/NzbDrone.Update/UpdateContainerBuilder.cs b/src/NzbDrone.Update/UpdateContainerBuilder.cs
index 47fcbe598..91aa048bb 100644
--- a/src/NzbDrone.Update/UpdateContainerBuilder.cs
+++ b/src/NzbDrone.Update/UpdateContainerBuilder.cs
@@ -10,7 +10,7 @@ public class UpdateContainerBuilder : ContainerBuilderBase
private UpdateContainerBuilder(IStartupContext startupContext, List assemblies)
: base(startupContext, assemblies)
{
- Container.Register();
+
}
public static IContainer Build(IStartupContext startupContext)
diff --git a/src/NzbDrone.Windows.Test/EnvironmentInfo/DotNetPlatformInfoFixture.cs b/src/NzbDrone.Windows.Test/EnvironmentInfo/DotNetPlatformInfoFixture.cs
index 2cc9856f3..7bfeb70e1 100644
--- a/src/NzbDrone.Windows.Test/EnvironmentInfo/DotNetPlatformInfoFixture.cs
+++ b/src/NzbDrone.Windows.Test/EnvironmentInfo/DotNetPlatformInfoFixture.cs
@@ -13,7 +13,7 @@ public class DotNetPlatformInfoFixture : TestBase
public void should_get_framework_version()
{
Subject.Version.Major.Should().Be(4);
- Subject.Version.Minor.Should().BeOneOf(0, 5, 6);
+ Subject.Version.Minor.Should().BeOneOf(0, 5, 6, 7, 8);
}
}
}
diff --git a/src/NzbDrone.Windows/EnvironmentInfo/DotNetPlatformInfo.cs b/src/NzbDrone.Windows/EnvironmentInfo/DotNetPlatformInfo.cs
index 929ad2f03..64a2bf90b 100644
--- a/src/NzbDrone.Windows/EnvironmentInfo/DotNetPlatformInfo.cs
+++ b/src/NzbDrone.Windows/EnvironmentInfo/DotNetPlatformInfo.cs
@@ -13,7 +13,6 @@ public DotNetPlatformInfo(Logger logger)
{
_logger = logger;
var version = GetFrameworkVersion();
- Environment.SetEnvironmentVariable("RUNTIME_VERSION", version.ToString());
Version = version;
}
@@ -33,6 +32,22 @@ private Version GetFrameworkVersion()
var releaseKey = (int)ndpKey.GetValue("Release");
+ if (releaseKey >= 528040)
+ {
+ return new Version(4, 8, 0);
+ }
+ if (releaseKey >= 461808)
+ {
+ return new Version(4, 7, 2);
+ }
+ if (releaseKey >= 461308)
+ {
+ return new Version(4, 7, 1);
+ }
+ if (releaseKey >= 460798)
+ {
+ return new Version(4, 7);
+ }
if (releaseKey >= 394802)
{
return new Version(4, 6, 2);
diff --git a/src/Radarr.Api.V2/Logs/LogFileModuleBase.cs b/src/Radarr.Api.V2/Logs/LogFileModuleBase.cs
index c68c40ce2..7db242260 100644
--- a/src/Radarr.Api.V2/Logs/LogFileModuleBase.cs
+++ b/src/Radarr.Api.V2/Logs/LogFileModuleBase.cs
@@ -3,6 +3,7 @@
using System.Linq;
using Nancy;
using Nancy.Responses;
+using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
using Radarr.Http;
@@ -44,7 +45,7 @@ private List GetLogFilesResponse()
Id = i + 1,
Filename = filename,
LastWriteTime = _diskProvider.FileGetLastWrite(file),
- ContentsUrl = string.Format("{0}/api/v3/{1}/{2}", _configFileProvider.UrlBase, Resource, filename),
+ ContentsUrl = string.Format("{0}/api/v2/{1}/{2}", _configFileProvider.UrlBase, Resource, filename),
DownloadUrl = string.Format("{0}/{1}/{2}", _configFileProvider.UrlBase, DownloadUrlRoot, filename)
});
}
@@ -54,6 +55,8 @@ private List GetLogFilesResponse()
private Response GetLogFileResponse(string filename)
{
+ LogManager.Flush();
+
var filePath = GetLogFilePath(filename);
if (!_diskProvider.FileExists(filePath))
diff --git a/src/Radarr.Api.V2/Movies/MovieEditorResource.cs b/src/Radarr.Api.V2/Movies/MovieEditorResource.cs
index 0f74af501..51ac3a058 100644
--- a/src/Radarr.Api.V2/Movies/MovieEditorResource.cs
+++ b/src/Radarr.Api.V2/Movies/MovieEditorResource.cs
@@ -4,7 +4,7 @@
namespace Radarr.Api.V2.Movies
{
- class MovieEditorResource
+ public class MovieEditorResource
{
public List MovieIds { get; set; }
public bool? Monitored { get; set; }
diff --git a/src/Radarr.Api.V2/System/SystemModule.cs b/src/Radarr.Api.V2/System/SystemModule.cs
index 25b5546a1..6957cce4c 100644
--- a/src/Radarr.Api.V2/System/SystemModule.cs
+++ b/src/Radarr.Api.V2/System/SystemModule.cs
@@ -64,6 +64,7 @@ private Response GetStatus()
IsLinux = OsInfo.IsLinux,
IsOsx = OsInfo.IsOsx,
IsWindows = OsInfo.IsWindows,
+ IsDocker = _osInfo.IsDocker,
Mode = _runtimeInfo.Mode,
Branch = _configFileProvider.Branch,
Authentication = _configFileProvider.AuthenticationMethod,
diff --git a/src/Radarr.sln b/src/Radarr.sln
index 400d33e87..0b5389717 100644
--- a/src/Radarr.sln
+++ b/src/Radarr.sln
@@ -41,8 +41,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platform", "Platform", "{4E
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonoTorrent", "MonoTorrent\MonoTorrent.csproj", "{411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CurlSharp", "ExternalModules\CurlSharp\CurlSharp\CurlSharp.csproj", "{74420A79-CC16-442C-8B1E-7C1B913844F0}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Radarr.Http", "Radarr.Http\Radarr.Http.csproj", "{C5953DAB-89DB-46D9-A401-D620F54B776E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Radarr.Api.V2", "Radarr.Api.V2\Radarr.Api.V2.csproj", "{38497DC6-E488-4B9E-A973-A1A7961B33C4}"
@@ -118,12 +116,6 @@ Global
{411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8}.Mono|x86.Build.0 = Release|x86
{411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8}.Release|x86.ActiveCfg = Release|x86
{411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8}.Release|x86.Build.0 = Release|x86
- {74420A79-CC16-442C-8B1E-7C1B913844F0}.Debug|x86.ActiveCfg = Debug|Any CPU
- {74420A79-CC16-442C-8B1E-7C1B913844F0}.Debug|x86.Build.0 = Debug|Any CPU
- {74420A79-CC16-442C-8B1E-7C1B913844F0}.Mono|x86.ActiveCfg = Release|Any CPU
- {74420A79-CC16-442C-8B1E-7C1B913844F0}.Mono|x86.Build.0 = Release|Any CPU
- {74420A79-CC16-442C-8B1E-7C1B913844F0}.Release|x86.ActiveCfg = Release|Any CPU
- {74420A79-CC16-442C-8B1E-7C1B913844F0}.Release|x86.Build.0 = Release|Any CPU
{C5953DAB-89DB-46D9-A401-D620F54B776E}.Debug|x86.ActiveCfg = Debug|x86
{C5953DAB-89DB-46D9-A401-D620F54B776E}.Debug|x86.Build.0 = Debug|x86
{C5953DAB-89DB-46D9-A401-D620F54B776E}.Mono|x86.ActiveCfg = Release|x86
@@ -279,7 +271,6 @@ Global
{F6FC6BE7-0847-4817-A1ED-223DC647C3D7} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA}
{4EACDBBC-BCD7-4765-A57B-3E08331E4749} = {57A04B72-8088-4F75-A582-1158CF8291F7}
{411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA}
- {74420A79-CC16-442C-8B1E-7C1B913844F0} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA}
{D9468BE6-8242-4E7F-9470-EE6FDA8832D0} = {57A04B72-8088-4F75-A582-1158CF8291F7}
{779D577B-2287-4FB8-8760-D653DBB87109} = {57A04B72-8088-4F75-A582-1158CF8291F7}
{175CE3A0-0D8C-48DB-9D8D-C7BBD9591813} = {57A04B72-8088-4F75-A582-1158CF8291F7}
diff --git a/src/SharedLiveTemplates.xml b/src/SharedLiveTemplates.xml
deleted file mode 100644
index da03090c5..000000000
--- a/src/SharedLiveTemplates.xml
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file