HttpClient

This commit is contained in:
Keivan Beigi 2014-09-11 16:49:41 -07:00
parent 3a287bf7e7
commit 2c1d3339d0
55 changed files with 995 additions and 582 deletions

View File

@ -9,13 +9,10 @@ namespace NzbDrone.Api.Update
public class UpdateModule : NzbDroneRestModule<UpdateResource>
{
private readonly IRecentUpdateProvider _recentUpdateProvider;
private readonly IInstallUpdates _installUpdateService;
public UpdateModule(IRecentUpdateProvider recentUpdateProvider,
IInstallUpdates installUpdateService)
public UpdateModule(IRecentUpdateProvider recentUpdateProvider)
{
_recentUpdateProvider = recentUpdateProvider;
_installUpdateService = installUpdateService;
GetResourceAll = GetRecentUpdates;
}

View File

@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Net;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Test.Common;
using NzbDrone.Test.Common.Categories;
namespace NzbDrone.Common.Test.Http
{
[TestFixture]
[IntegrationTest]
public class RestClientFixture : TestBase<HttpClient>
{
[Test]
public void should_execute_simple_get()
{
var request = new HttpRequest("http://eu.httpbin.org/get");
var response = Subject.Execute(request);
response.Content.Should().NotBeNullOrWhiteSpace();
}
[Test]
public void should_execute_typed_get()
{
var request = new HttpRequest("http://eu.httpbin.org/get");
var response = Subject.Get<HttpBinResource>(request);
response.Resource.Url.Should().Be(request.Url.ToString());
}
[TestCase("gzip")]
public void should_execute_get_using_gzip(string compression)
{
var request = new HttpRequest("http://eu.httpbin.org/" + compression);
var response = Subject.Get<HttpBinResource>(request);
response.Resource.Headers["Accept-Encoding"].ToString().Should().Be(compression);
response.Headers.ContentLength.Should().BeLessOrEqualTo(response.Content.Length);
}
[TestCase(HttpStatusCode.Unauthorized)]
[TestCase(HttpStatusCode.Forbidden)]
[TestCase(HttpStatusCode.NotFound)]
[TestCase(HttpStatusCode.InternalServerError)]
[TestCase(HttpStatusCode.ServiceUnavailable)]
[TestCase(HttpStatusCode.BadGateway)]
public void should_throw_on_unsuccessful_status_codes(HttpStatusCode statusCode)
{
var request = new HttpRequest("http://eu.httpbin.org/status/" + (int)statusCode);
var exception = Assert.Throws<HttpException>(() => Subject.Get<HttpBinResource>(request));
exception.Response.StatusCode.Should().Be(statusCode);
}
[TestCase(HttpStatusCode.Moved)]
[TestCase(HttpStatusCode.MovedPermanently)]
public void should_not_follow_redirects_when_not_in_production(HttpStatusCode statusCode)
{
var request = new HttpRequest("http://eu.httpbin.org/status/" + (int)statusCode);
Assert.Throws<Exception>(() => Subject.Get<HttpBinResource>(request));
}
}
public class HttpBinResource
{
public Dictionary<string, object> Headers { get; set; }
public string Origin { get; set; }
public string Url { get; set; }
}
}

View File

@ -0,0 +1,22 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Test.Common;
namespace NzbDrone.Common.Test.Http
{
[TestFixture]
public class HttpRequestBuilderFixture : TestBase
{
[Test]
public void should_remove_duplicated_slashes()
{
var builder = new HttpRequestBuilder("http://domain/");
var request = builder.Build("/v1/");
request.Url.ToString().Should().Be("http://domain/v1/");
}
}
}

View File

@ -0,0 +1,29 @@
using System;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Http;
namespace NzbDrone.Common.Test.Http
{
[TestFixture]
public class HttpRequestFixture
{
[TestCase("http://host/{seg}/some", "http://host/dir/some")]
[TestCase("http://host/some/{seg}", "http://host/some/dir")]
public void should_add_single_segment_url_segments(string url, string result)
{
var request = new HttpRequest(url);
request.AddSegment("seg", "dir");
request.Url.Should().Be(result);
}
[Test]
public void shouldnt_add_value_for_nonexisting_segment()
{
var request = new HttpRequest("http://host/{seg}/some");
Assert.Throws<InvalidOperationException>(() => request.AddSegment("seg2", "dir"));
}
}
}

View File

@ -73,6 +73,9 @@
<Compile Include="EnvironmentProviderTest.cs" />
<Compile Include="EnvironmentTests\EnvironmentProviderTest.cs" />
<Compile Include="EnvironmentTests\StartupArgumentsFixture.cs" />
<Compile Include="Http\HttpClientFixture.cs" />
<Compile Include="Http\HttpRequestBuilderFixture.cs" />
<Compile Include="Http\HttpRequestFixture.cs" />
<Compile Include="InstrumentationTests\CleanseLogMessageFixture.cs" />
<Compile Include="LevenshteinDistanceFixture.cs" />
<Compile Include="PathExtensionFixture.cs" />

View File

@ -26,13 +26,5 @@ namespace NzbDrone.Common.Test
Assert.Throws<ArgumentException>(() => Subject.DownloadString(url));
ExceptionVerification.ExpectedWarns(1);
}
[Test]
public void should_get_headers()
{
Subject.GetHeader("http://www.google.com").Should().NotBeEmpty();
}
}
}

View File

@ -0,0 +1,19 @@
using NzbDrone.Common.Http;
namespace NzbDrone.Common.Cloud
{
public interface IDroneServicesRequestBuilder
{
HttpRequest Build(string path);
}
public class DroneServicesHttpRequestBuilder : HttpRequestBuilder, IDroneServicesRequestBuilder
{
private const string ROOT_URL = "http://services.nzbdrone.com/v1/";
public DroneServicesHttpRequestBuilder()
: base(ROOT_URL)
{
}
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Net;
namespace NzbDrone.Common.Http
{
public class GZipWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
var request = (HttpWebRequest)base.GetWebRequest(address);
request.AutomaticDecompression = DecompressionMethods.GZip;
return request;
}
}
}

View File

@ -0,0 +1,160 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common.Http
{
public interface IHttpClient
{
HttpResponse Execute(HttpRequest request);
void DownloadFile(string url, string fileName);
HttpResponse Get(HttpRequest request);
HttpResponse<T> Get<T>(HttpRequest request) where T : new();
HttpResponse Head(HttpRequest request);
}
public class HttpClient : IHttpClient
{
private readonly Logger _logger;
private readonly string _userAgent;
public HttpClient(Logger logger)
{
_logger = logger;
_userAgent = String.Format("NzbDrone {0}", BuildInfo.Version);
ServicePointManager.DefaultConnectionLimit = 12;
}
public HttpResponse Execute(HttpRequest request)
{
_logger.Trace(request);
var webRequest = (HttpWebRequest)WebRequest.Create(request.Url);
// Deflate is not a standard and could break depending on implementation.
// we should just stick with the more compatible Gzip
//http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net
webRequest.AutomaticDecompression = DecompressionMethods.GZip;
webRequest.Credentials = request.NetworkCredential;
webRequest.Method = request.Method.ToString();
webRequest.KeepAlive = false;
if (!RuntimeInfoBase.IsProduction)
{
webRequest.AllowAutoRedirect = false;
}
var stopWatch = Stopwatch.StartNew();
if (!request.Body.IsNullOrWhiteSpace())
{
var bytes = new byte[request.Body.Length * sizeof(char)];
Buffer.BlockCopy(request.Body.ToCharArray(), 0, bytes, 0, bytes.Length);
webRequest.ContentLength = bytes.Length;
using (var writeStream = webRequest.GetRequestStream())
{
writeStream.Write(bytes, 0, bytes.Length);
}
}
HttpWebResponse httpWebResponse;
try
{
httpWebResponse = (HttpWebResponse)webRequest.GetResponse();
}
catch (WebException e)
{
httpWebResponse = (HttpWebResponse)e.Response;
}
string content = null;
using (var responseStream = httpWebResponse.GetResponseStream())
{
if (responseStream != null)
{
using (var reader = new StreamReader(responseStream))
{
content = reader.ReadToEnd();
}
}
}
stopWatch.Stop();
var response = new HttpResponse(request, new HttpHeader(httpWebResponse.Headers), content, httpWebResponse.StatusCode);
_logger.Trace("{0} ({1:n0} ms)", response, stopWatch.ElapsedMilliseconds);
if (!RuntimeInfoBase.IsProduction &&
(response.StatusCode == HttpStatusCode.Moved ||
response.StatusCode == HttpStatusCode.MovedPermanently))
{
throw new Exception("Server requested a redirect to [" + response.Headers["Location"] + "]. Update the request URL to avoid this redirect.");
}
if (!request.SuppressHttpError && response.HasHttpError)
{
_logger.Warn("HTTP Error - {0}", response);
throw new HttpException(request, response);
}
return response;
}
public void DownloadFile(string url, string fileName)
{
try
{
var fileInfo = new FileInfo(fileName);
if (fileInfo.Directory != null && !fileInfo.Directory.Exists)
{
fileInfo.Directory.Create();
}
_logger.Debug("Downloading [{0}] to [{1}]", url, fileName);
var stopWatch = Stopwatch.StartNew();
var webClient = new GZipWebClient();
webClient.Headers.Add(HttpRequestHeader.UserAgent, _userAgent);
webClient.DownloadFile(url, fileName);
stopWatch.Stop();
_logger.Debug("Downloading Completed. took {0:0}s", stopWatch.Elapsed.Seconds);
}
catch (WebException e)
{
_logger.Warn("Failed to get response from: {0} {1}", url, e.Message);
throw;
}
catch (Exception e)
{
_logger.WarnException("Failed to get response from: " + url, e);
throw;
}
}
public HttpResponse Get(HttpRequest request)
{
request.Method = HttpMethod.GET;
return Execute(request);
}
public HttpResponse<T> Get<T>(HttpRequest request) where T : new()
{
var response = Get(request);
return new HttpResponse<T>(response);
}
public HttpResponse Head(HttpRequest request)
{
request.Method = HttpMethod.HEAD;
return Execute(request);
}
}
}

View File

@ -0,0 +1,27 @@
using System;
namespace NzbDrone.Common.Http
{
public class HttpException : Exception
{
public HttpRequest Request { get; private set; }
public HttpResponse Response { get; private set; }
public HttpException(HttpRequest request, HttpResponse response)
: base(string.Format("HTTP request failed: [{0}] [{1}] at [{2}]", (int)response.StatusCode, request.Method, request.Url.ToString()))
{
Request = request;
Response = response;
}
public override string ToString()
{
if (Response != null)
{
return base.ToString() + Environment.NewLine + Response.Content;
}
return base.ToString();
}
}
}

View File

@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
namespace NzbDrone.Common.Http
{
public class HttpHeader : Dictionary<string, object>
{
public HttpHeader(NameValueCollection headers)
{
foreach (var key in headers.AllKeys)
{
this[key] = headers[key];
}
}
public HttpHeader()
{
}
public long? ContentLength
{
get
{
if (!ContainsKey("Content-Length"))
{
return null;
}
return Convert.ToInt64(this["Content-Length"]);
}
set
{
this["Content-Length"] = value;
}
}
public string ContentType
{
get
{
if (!ContainsKey("Content-Type"))
{
return null;
}
return this["Content-Type"].ToString();
}
set
{
this["Content-Type"] = value;
}
}
public string Accept
{
get
{
if (!ContainsKey("Accept"))
{
return null;
}
return this["Accept"].ToString();
}
set
{
this["Accept"] = value;
}
}
}
}

View File

@ -0,0 +1,13 @@
namespace NzbDrone.Common.Http
{
public enum HttpMethod
{
GET,
PUT,
POST,
HEAD,
DELETE,
PATCH,
OPTIONS
}
}

View File

@ -1,40 +1,23 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common.Http
{
[Obsolete("Use IHttpClient")]
public interface IHttpProvider
{
string DownloadString(string url);
string DownloadString(string url, string username, string password);
string DownloadString(string url, ICredentials credentials);
Dictionary<string, string> GetHeader(string url);
Stream DownloadStream(string url, NetworkCredential credential = null);
void DownloadFile(string url, string fileName);
string PostCommand(string address, string username, string password, string command);
}
[Obsolete("Use HttpProvider")]
public class HttpProvider : IHttpProvider
{
private class GZipWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
return request;
}
}
private readonly Logger _logger;
public const string CONTENT_LENGTH_HEADER = "Content-Length";
private readonly string _userAgent;
@ -55,7 +38,7 @@ namespace NzbDrone.Common.Http
return DownloadString(url, new NetworkCredential(username, password));
}
public string DownloadString(string url, ICredentials identity)
private string DownloadString(string url, ICredentials identity)
{
try
{
@ -75,81 +58,6 @@ namespace NzbDrone.Common.Http
}
}
public Dictionary<string, string> GetHeader(string url)
{
var headers = new Dictionary<string, string>();
var request = WebRequest.Create(url);
request.Method = "HEAD";
var response = request.GetResponse();
foreach (var key in response.Headers.AllKeys)
{
headers.Add(key, response.Headers[key]);
}
return headers;
}
public Stream DownloadStream(string url, NetworkCredential credential = null)
{
var request = (HttpWebRequest)WebRequest.Create(url);
request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
request.UserAgent = _userAgent;
request.Timeout = 20 * 1000;
request.Credentials = credential;
var response = request.GetResponse();
return response.GetResponseStream();
}
public void DownloadFile(string url, string fileName)
{
try
{
var fileInfo = new FileInfo(fileName);
if (fileInfo.Directory != null && !fileInfo.Directory.Exists)
{
fileInfo.Directory.Create();
}
_logger.Debug("Downloading [{0}] to [{1}]", url, fileName);
var stopWatch = Stopwatch.StartNew();
var webClient = new GZipWebClient();
webClient.Headers.Add(HttpRequestHeader.UserAgent, _userAgent);
webClient.DownloadFile(url, fileName);
stopWatch.Stop();
_logger.Debug("Downloading Completed. took {0:0}s", stopWatch.Elapsed.Seconds);
}
catch (WebException e)
{
_logger.Warn("Failed to get response from: {0} {1}", url, e.Message);
throw;
}
catch (Exception e)
{
_logger.WarnException("Failed to get response from: " + url, e);
throw;
}
}
public string PostCommand(string address, string username, string password, string command)
{
address = String.Format("http://{0}/jsonrpc", address);
_logger.Debug("Posting command: {0}, to {1}", command, address);
byte[] byteArray = Encoding.ASCII.GetBytes(command);
var wc = new NzbDroneWebClient();
wc.Credentials = new NetworkCredential(username, password);
var response = wc.UploadData(address, "POST", byteArray);
var text = Encoding.ASCII.GetString(response);
return text.Replace("&nbsp;", " ");
}
}
}

View File

@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Net;
namespace NzbDrone.Common.Http
{
public class HttpRequest
{
private readonly Dictionary<string, string> _segments;
public HttpRequest(string url)
{
UriBuilder = new UriBuilder(url);
Headers = new HttpHeader();
_segments = new Dictionary<string, string>();
Headers.Accept = "application/json";
}
public UriBuilder UriBuilder { get; private set; }
public Uri Url
{
get
{
var uri = UriBuilder.Uri.ToString();
foreach (var segment in _segments)
{
uri = uri.Replace(segment.Key, segment.Value);
}
return new Uri(uri);
}
}
public HttpMethod Method { get; set; }
public HttpHeader Headers { get; set; }
public string Body { get; set; }
public NetworkCredential NetworkCredential { get; set; }
public bool SuppressHttpError { get; set; }
public override string ToString()
{
if (Body == null)
{
return string.Format("Req: [{0}] {1}", Method, Url);
}
return string.Format("Req: [{0}] {1} {2} {3}", Method, Url, Environment.NewLine, Body);
}
public void AddSegment(string segment, string value)
{
var key = "{" + segment + "}";
if (!UriBuilder.Uri.ToString().Contains(key))
{
throw new InvalidOperationException("Segment " + key +" is not defined in Uri");
}
_segments.Add(key, value);
}
}
}

View File

@ -0,0 +1,40 @@
using System;
using System.Net;
namespace NzbDrone.Common.Http
{
public class HttpRequestBuilder
{
public Uri BaseUri { get; private set; }
public bool SupressHttpError { get; set; }
public NetworkCredential NetworkCredential { get; set; }
public Action<HttpRequest> PostProcess { get; set; }
public HttpRequestBuilder(string baseUri)
{
BaseUri = new Uri(baseUri);
}
public virtual HttpRequest Build(string path)
{
if (BaseUri.ToString().EndsWith("/"))
{
path = path.TrimStart('/');
}
var request = new HttpRequest(BaseUri + path)
{
SuppressHttpError = SupressHttpError,
NetworkCredential = NetworkCredential
};
if (PostProcess != null)
{
PostProcess(request);
}
return request;
}
}
}

View File

@ -0,0 +1,65 @@
using System;
using System.IO;
using System.Net;
using NzbDrone.Common.Serializer;
namespace NzbDrone.Common.Http
{
public class HttpResponse
{
public HttpResponse(HttpRequest request, HttpHeader headers, string content, HttpStatusCode statusCode)
{
Request = request;
Headers = headers;
Content = content;
StatusCode = statusCode;
}
public HttpRequest Request { get; private set; }
public HttpHeader Headers { get; private set; }
public HttpStatusCode StatusCode { get; private set; }
public string Content { get; private set; }
public bool HasHttpError
{
get
{
return (int)StatusCode >= 400;
}
}
public override string ToString()
{
var result = string.Format("Res: [{0}] {1} : {2}.{3}", Request.Method, Request.Url, (int)StatusCode, StatusCode);
if (HasHttpError)
{
result += Environment.NewLine + Content;
}
return result;
}
public Stream GetStream()
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(Content);
writer.Flush();
stream.Position = 0;
return stream;
}
}
public class HttpResponse<T> : HttpResponse where T : new()
{
public HttpResponse(HttpResponse response)
: base(response.Request, response.Headers, response.Content, response.StatusCode)
{
Resource = Json.Deserialize<T>(response.Content);
}
public T Resource { get; private set; }
}
}

View File

@ -0,0 +1,21 @@
using System;
namespace NzbDrone.Common.Http
{
public static class UriExtensions
{
public static void SetQueryParam(this UriBuilder uriBuilder, string key, object value)
{
var query = uriBuilder.Query;
if (query.IsNotNullOrWhiteSpace())
{
query += "&";
}
uriBuilder.Query = query.Trim('?') + (key + "=" + value);
}
}
}

View File

@ -58,16 +58,13 @@
<Reference Include="NLog">
<HintPath>..\packages\NLog.2.1.0\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="RestSharp, Version=104.4.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\RestSharp.104.4.0\lib\net4\RestSharp.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ArchiveService.cs" />
<Compile Include="Cache\Cached.cs" />
<Compile Include="Cache\CacheManager.cs" />
<Compile Include="Cache\ICached.cs" />
<Compile Include="Cloud\CloudClient.cs" />
<Compile Include="Composition\Container.cs" />
<Compile Include="Composition\ContainerBuilderBase.cs" />
<Compile Include="Composition\IContainer.cs" />
@ -114,10 +111,21 @@
<Compile Include="Extensions\Base64Extentions.cs" />
<Compile Include="Extensions\StreamExtensions.cs" />
<Compile Include="HashUtil.cs" />
<Compile Include="Http\GZipWebClient.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Http\HttpClient.cs" />
<Compile Include="Http\HttpException.cs" />
<Compile Include="Http\HttpHeader.cs" />
<Compile Include="Http\HttpMethod.cs" />
<Compile Include="Http\HttpProvider.cs" />
<Compile Include="Http\HttpRequest.cs" />
<Compile Include="Http\HttpResponse.cs" />
<Compile Include="Http\NzbDroneWebClient.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Http\HttpRequestBuilder.cs" />
<Compile Include="Http\UriExtensions.cs" />
<Compile Include="IEnumerableExtensions.cs" />
<Compile Include="Instrumentation\CleanseLogMessage.cs" />
<Compile Include="Instrumentation\ExceptronTarget.cs" />

View File

@ -74,6 +74,11 @@ namespace NzbDrone.Common
return String.IsNullOrWhiteSpace(text);
}
public static bool IsNotNullOrWhiteSpace(this string text)
{
return !String.IsNullOrWhiteSpace(text);
}
public static bool ContainsIgnoreCase(this string text, string contains)
{
return text.IndexOf(contains, StringComparison.InvariantCultureIgnoreCase) > -1;

View File

@ -3,6 +3,5 @@
<package id="loggly-csharp" version="2.3" targetFramework="net40" />
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net40" />
<package id="NLog" version="2.1.0" targetFramework="net40" />
<package id="RestSharp" version="104.4.0" targetFramework="net40" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net40" />
</packages>

View File

@ -0,0 +1,28 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.DataAugmentation.DailySeries;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using NzbDrone.Test.Common.Categories;
namespace NzbDrone.Core.Test.DataAugmentation.DailySeries
{
[TestFixture]
[IntegrationTest]
public class DailySeriesDataProxyFixture : CoreTest<DailySeriesDataProxy>
{
[SetUp]
public void Setup()
{
UseRealHttp();
}
[Test]
public void should_get_list_of_daily_series()
{
var list = Subject.GetDailySeriesIds();
list.Should().NotBeEmpty();
list.Should().OnlyHaveUniqueItems();
}
}
}

View File

@ -1,53 +1,33 @@
using System;
using System.Net;
using FluentAssertions;
using Newtonsoft.Json;
using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Common.Http;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.Categories;
namespace NzbDrone.Core.Test.DataAugmentationFixture.Scene
{
[TestFixture]
[IntegrationTest]
public class SceneMappingProxyFixture : CoreTest<SceneMappingProxy>
{
private const string SCENE_MAPPING_URL = "http://services.nzbdrone.com/v1/SceneMapping";
[SetUp]
public void Setup()
{
UseRealHttp();
}
[Test]
public void fetch_should_return_list_of_mappings()
{
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString(SCENE_MAPPING_URL))
.Returns(ReadAllText("Files", "SceneMappings.json"));
var mappings = Subject.Fetch();
mappings.Should().NotBeEmpty();
mappings.Should().NotContain(c => String.IsNullOrWhiteSpace(c.SearchTerm));
mappings.Should().NotContain(c => String.IsNullOrWhiteSpace(c.Title));
mappings.Should().NotContain(c => c.TvdbId == 0);
mappings.Should().NotContain(c => c.SearchTerm.IsNullOrWhiteSpace());
mappings.Should().NotContain(c => c.Title.IsNullOrWhiteSpace());
mappings.Should().Contain(c => c.SeasonNumber > 0);
}
[Test]
public void should_throw_on_server_error()
{
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString(SCENE_MAPPING_URL))
.Throws(new WebException());
Assert.Throws<WebException>(() => Subject.Fetch());
}
[Test]
public void should_throw_on_bad_json()
{
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString(SCENE_MAPPING_URL))
.Returns("bad json");
Assert.Throws<JsonReaderException>(() => Subject.Fetch());
}
}
}

View File

@ -5,13 +5,9 @@ using Moq;
using NUnit.Framework;
using FluentAssertions;
using NzbDrone.Test.Common;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Common;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Http;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients;
using NzbDrone.Core.Download.Clients.UsenetBlackhole;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
@ -46,7 +42,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
protected void WithFailedDownload()
{
Mocker.GetMock<IHttpProvider>()
Mocker.GetMock<IHttpClient>()
.Setup(c => c.DownloadFile(It.IsAny<string>(), It.IsAny<string>()))
.Throws(new WebException());
}
@ -84,7 +80,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
Subject.Download(remoteEpisode);
Mocker.GetMock<IHttpProvider>().Verify(c => c.DownloadFile(_downloadUrl, _filePath), Times.Once());
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(_downloadUrl, _filePath), Times.Once());
}
[Test]
@ -98,7 +94,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
Subject.Download(remoteEpisode);
Mocker.GetMock<IHttpProvider>().Verify(c => c.DownloadFile(It.IsAny<string>(), expectedFilename), Times.Once());
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(It.IsAny<string>(), expectedFilename), Times.Once());
}
[Test]

View File

@ -1,10 +1,10 @@
using System;
using System.Text;
using System.Linq;
using System.Net;
using System.Collections.Generic;
using Moq;
using NUnit.Framework;
using FluentAssertions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Parser;
@ -30,6 +30,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
Mocker.GetMock<IParsingService>()
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), null))
.Returns(CreateRemoteEpisode());
Mocker.GetMock<IHttpClient>()
.Setup(c => c.Get(It.IsAny<HttpRequest>()))
.Returns(new HttpResponse(null, null, "", HttpStatusCode.OK));
}
protected virtual RemoteEpisode CreateRemoteEpisode()

View File

@ -51,14 +51,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
};
}
private void WithExistingFile()
{
Mocker.GetMock<IDiskProvider>().Setup(c => c.FileExists(_nzbPath)).Returns(true);
}
private void WithFailedDownload()
{
Mocker.GetMock<IHttpProvider>().Setup(c => c.DownloadFile(It.IsAny<string>(), It.IsAny<string>())).Throws(new WebException());
Mocker.GetMock<IHttpClient>().Setup(c => c.DownloadFile(It.IsAny<string>(), It.IsAny<string>())).Throws(new WebException());
}
[Test]
@ -66,7 +61,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
{
Subject.Download(_remoteEpisode);
Mocker.GetMock<IHttpProvider>().Verify(c => c.DownloadFile(_nzbUrl, _nzbPath), Times.Once());
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(_nzbUrl, _nzbPath), Times.Once());
}
@ -102,7 +97,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
Subject.Download(_remoteEpisode);
Mocker.GetMock<IHttpProvider>().Verify(c => c.DownloadFile(It.IsAny<string>(), expectedFilename), Times.Once());
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(It.IsAny<string>(), expectedFilename), Times.Once());
}
}
}

View File

@ -1,32 +0,0 @@
[
{
"title": "Adventure Time",
"searchTitle": "Adventure Time",
"season": -1,
"tvdbId": 152831
},
{
"title": "Americas Funniest Home Videos",
"searchTitle": "Americas Funniest Home Videos",
"season": -1,
"tvdbId": 76235
},
{
"title": "Antiques Roadshow UK",
"searchTitle": "Antiques Roadshow UK",
"season": -1,
"tvdbId": 83774
},
{
"title": "Aqua Something You Know Whatever",
"searchTitle": "Aqua Something You Know Whatever",
"season": 9,
"tvdbId": 77120
},
{
"title": "Aqua Teen Hunger Force",
"searchTitle": "Aqua Teen Hunger Force",
"season": -1,
"tvdbId": 77120
}
]

View File

@ -1,5 +1,6 @@
using System.IO;
using NUnit.Framework;
using NzbDrone.Common.Cloud;
using NzbDrone.Common.Http;
using NzbDrone.Test.Common;
@ -15,6 +16,8 @@ namespace NzbDrone.Core.Test.Framework
protected void UseRealHttp()
{
Mocker.SetConstant<IHttpProvider>(new HttpProvider(TestLogger));
Mocker.SetConstant<IHttpClient>(new HttpClient(TestLogger));
Mocker.SetConstant<IDroneServicesRequestBuilder>(new DroneServicesHttpRequestBuilder());
}
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Net;
using FluentAssertions;
using Moq;
using NUnit.Framework;
@ -14,14 +15,14 @@ namespace NzbDrone.Core.Test.MediaCoverTests
[TestFixture]
public class CoverAlreadyExistsSpecificationFixture : CoreTest<CoverAlreadyExistsSpecification>
{
private Dictionary<string, string> _headers;
private HttpResponse _httpResponse;
[SetUp]
public void Setup()
{
_headers = new Dictionary<string, string>();
_httpResponse = new HttpResponse(null, new HttpHeader(), null, HttpStatusCode.OK);
Mocker.GetMock<IDiskProvider>().Setup(c => c.GetFileSize(It.IsAny<string>())).Returns(100);
Mocker.GetMock<IHttpProvider>().Setup(c => c.GetHeader(It.IsAny<string>())).Returns(_headers);
Mocker.GetMock<IHttpClient>().Setup(c => c.Head(It.IsAny<HttpRequest>())).Returns(_httpResponse);
}
@ -50,7 +51,7 @@ namespace NzbDrone.Core.Test.MediaCoverTests
public void should_return_false_if_file_exists_but_diffrent_size()
{
GivenExistingFileSize(100);
_headers.Add(HttpProvider.CONTENT_LENGTH_HEADER, "200");
_httpResponse.Headers.ContentLength = 200;
Subject.AlreadyExists("http://url", "c:\\file.exe").Should().BeFalse();
}
@ -60,8 +61,7 @@ namespace NzbDrone.Core.Test.MediaCoverTests
public void should_return_ture_if_file_exists_and_same_size()
{
GivenExistingFileSize(100);
_headers.Add(HttpProvider.CONTENT_LENGTH_HEADER, "100");
_httpResponse.Headers.ContentLength = 100;
Subject.AlreadyExists("http://url", "c:\\file.exe").Should().BeTrue();
}
@ -70,8 +70,6 @@ namespace NzbDrone.Core.Test.MediaCoverTests
{
GivenExistingFileSize(100);
Subject.AlreadyExists("http://url", "c:\\file.exe").Should().BeFalse();
ExceptionVerification.ExpectedWarns(1);
}
}
}

View File

@ -3,8 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.Rest;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
@ -16,12 +16,27 @@ namespace NzbDrone.Core.Test.MetadataSourceTests
[IntegrationTest]
public class TraktProxyFixture : CoreTest<TraktProxy>
{
[SetUp]
public void Setup()
{
UseRealHttp();
}
[TestCase("The Simpsons", "The Simpsons")]
[TestCase("South Park", "South Park")]
[TestCase("Franklin & Bash", "Franklin & Bash")]
[TestCase("Mr. D", "Mr. D")]
[TestCase("Rob & Big", "Rob and Big")]
[TestCase("M*A*S*H", "M*A*S*H")]
[TestCase("imdb:tt0436992", "Doctor Who (2005)")]
[TestCase("imdb:0436992", "Doctor Who (2005)")]
[TestCase("IMDB:0436992", "Doctor Who (2005)")]
[TestCase("IMDB: 0436992 ", "Doctor Who (2005)")]
[TestCase("tvdb:78804", "Doctor Who (2005)")]
[TestCase("TVDB:78804", "Doctor Who (2005)")]
[TestCase("TVDB: 78804 ", "Doctor Who (2005)")]
public void successful_search(string title, string expected)
{
var result = Subject.SearchForNewSeries(title);
@ -52,7 +67,7 @@ namespace NzbDrone.Core.Test.MetadataSourceTests
[Test]
public void getting_details_of_invalid_series()
{
Assert.Throws<RestException>(() => Subject.GetSeriesInfo(Int32.MaxValue));
Assert.Throws<HttpException>(() => Subject.GetSeriesInfo(Int32.MaxValue));
ExceptionVerification.ExpectedWarns(1);
}

View File

@ -1,14 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.MetadataSource.Tvdb;
using NzbDrone.Core.Rest;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
using NzbDrone.Test.Common.Categories;
namespace NzbDrone.Core.Test.MetadataSourceTests
@ -17,70 +13,15 @@ namespace NzbDrone.Core.Test.MetadataSourceTests
[IntegrationTest]
public class TvdbProxyFixture : CoreTest<TvdbProxy>
{
// [TestCase("The Simpsons", "The Simpsons")]
// [TestCase("South Park", "South Park")]
// [TestCase("Franklin & Bash", "Franklin & Bash")]
// [TestCase("Mr. D", "Mr. D")]
// [TestCase("Rob & Big", "Rob and Big")]
// [TestCase("M*A*S*H", "M*A*S*H")]
// public void successful_search(string title, string expected)
// {
// var result = Subject.SearchForNewSeries(title);
//
// result.Should().NotBeEmpty();
//
// result[0].Title.Should().Be(expected);
// }
//
// [Test]
// public void no_search_result()
// {
// var result = Subject.SearchForNewSeries(Guid.NewGuid().ToString());
// result.Should().BeEmpty();
// }
[TestCase(88031)]
[TestCase(179321)]
public void should_be_able_to_get_series_detail(int tvdbId)
{
var details = Subject.GetSeriesInfo(tvdbId);
UseRealHttp();
//ValidateSeries(details.Item1);
ValidateEpisodes(details.Item2);
}
var episodes = Subject.GetEpisodeInfo(tvdbId);
// [Test]
// public void getting_details_of_invalid_series()
// {
// Assert.Throws<RestException>(() => Subject.GetSeriesInfo(Int32.MaxValue));
//
// ExceptionVerification.ExpectedWarns(1);
// }
//
// [Test]
// public void should_not_have_period_at_start_of_title_slug()
// {
// var details = Subject.GetSeriesInfo(79099);
//
// details.Item1.TitleSlug.Should().Be("dothack");
// }
private void ValidateSeries(Series series)
{
series.Should().NotBeNull();
series.Title.Should().NotBeNullOrWhiteSpace();
series.CleanTitle.Should().Be(Parser.Parser.CleanSeriesTitle(series.Title));
series.Overview.Should().NotBeNullOrWhiteSpace();
series.AirTime.Should().NotBeNullOrWhiteSpace();
series.FirstAired.Should().HaveValue();
series.FirstAired.Value.Kind.Should().Be(DateTimeKind.Utc);
series.Images.Should().NotBeEmpty();
series.ImdbId.Should().NotBeNullOrWhiteSpace();
series.Network.Should().NotBeNullOrWhiteSpace();
series.Runtime.Should().BeGreaterThan(0);
series.TitleSlug.Should().NotBeNullOrWhiteSpace();
series.TvRageId.Should().BeGreaterThan(0);
series.TvdbId.Should().BeGreaterThan(0);
ValidateEpisodes(episodes);
}
private void ValidateEpisodes(List<Episode> episodes)
@ -91,30 +32,10 @@ namespace NzbDrone.Core.Test.MetadataSourceTests
.Max(e => e.Count()).Should().Be(1);
episodes.Should().Contain(c => c.SeasonNumber > 0);
// episodes.Should().Contain(c => !string.IsNullOrWhiteSpace(c.Overview));
foreach (var episode in episodes)
{
ValidateEpisode(episode);
//if atleast one episdoe has title it means parse it working.
// episodes.Should().Contain(c => !string.IsNullOrWhiteSpace(c.Title));
}
episodes.Should().OnlyContain(c => c.SeasonNumber > 0 || c.EpisodeNumber > 0);
}
private void ValidateEpisode(Episode episode)
{
episode.Should().NotBeNull();
//TODO: Is there a better way to validate that episode number or season number is greater than zero?
(episode.EpisodeNumber + episode.SeasonNumber).Should().NotBe(0);
episode.Should().NotBeNull();
// if (episode.AirDateUtc.HasValue)
// {
// episode.AirDateUtc.Value.Kind.Should().Be(DateTimeKind.Utc);
// }
}
}
}

View File

@ -107,6 +107,7 @@
<Compile Include="Configuration\ConfigServiceFixture.cs" />
<Compile Include="DataAugmentationFixture\Scene\SceneMappingProxyFixture.cs" />
<Compile Include="DataAugmentationFixture\Scene\SceneMappingServiceFixture.cs" />
<Compile Include="DataAugmentation\DailySeries\DailySeriesDataProxyFixture.cs" />
<Compile Include="Datastore\BasicRepositoryFixture.cs" />
<Compile Include="Datastore\Converters\ProviderSettingConverterFixture.cs" />
<Compile Include="Datastore\DatabaseFixture.cs" />
@ -380,9 +381,6 @@
</Content>
</ItemGroup>
<ItemGroup>
<None Include="Files\SceneMappings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Files\TestArchive.tar.gz">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>

View File

@ -24,6 +24,8 @@ namespace NzbDrone.Core.Test.TvTests
[TestFixtureSetUp]
public void TestFixture()
{
UseRealHttp();
_gameOfThrones = Mocker.Resolve<TraktProxy>().GetSeriesInfo(121361);//Game of thrones
// Remove specials.

View File

@ -1,6 +1,7 @@
using System;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Update;
@ -12,7 +13,7 @@ namespace NzbDrone.Core.Test.UpdateTests
public void no_update_when_version_higher()
{
UseRealHttp();
Subject.GetLatestUpdate("master", new Version(10,0)).Should().BeNull();
Subject.GetLatestUpdate("master", new Version(10, 0)).Should().BeNull();
}
[Test]
@ -21,5 +22,21 @@ namespace NzbDrone.Core.Test.UpdateTests
UseRealHttp();
Subject.GetLatestUpdate("master", new Version(2, 0)).Should().NotBeNull();
}
[Test]
public void should_get_recent_updates()
{
const string branch = "master";
UseRealHttp();
var recent = Subject.GetRecentUpdates(branch, 2);
recent.Should().NotBeEmpty();
recent.Should().OnlyContain(c => c.Hash.IsNotNullOrWhiteSpace());
recent.Should().OnlyContain(c => c.FileName.Contains("Drone.master.2"));
recent.Should().OnlyContain(c => c.ReleaseDate.Year == 2014);
recent.Should().OnlyContain(c => c.Changes.New != null);
recent.Should().OnlyContain(c => c.Changes.Fixed != null);
}
}
}

View File

@ -104,7 +104,7 @@ namespace NzbDrone.Core.Test.UpdateTests
Subject.Execute(new ApplicationUpdateCommand());
Mocker.GetMock<IHttpProvider>().Verify(c => c.DownloadFile(_updatePackage.Url, updateArchive));
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(_updatePackage.Url, updateArchive));
}
[Test]
@ -124,8 +124,6 @@ namespace NzbDrone.Core.Test.UpdateTests
Subject.Execute(new ApplicationUpdateCommand());
Mocker.GetMock<IDiskProvider>().Verify(c => c.MoveFolder(updateClientFolder, _sandboxFolder));
}

View File

@ -0,0 +1,7 @@
namespace NzbDrone.Core.DataAugmentation.DailySeries
{
public class DailySeries
{
public int TvdbId { get; set; }
}
}

View File

@ -1,27 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Common;
using NzbDrone.Common.Cloud;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
namespace NzbDrone.Core.DataAugmentation.DailySeries
{
public interface IDailySeriesDataProxy
{
IEnumerable<int> GetDailySeriesIds();
bool IsDailySeries(int tvdbid);
}
public class DailySeriesDataProxy : IDailySeriesDataProxy
{
private readonly IHttpProvider _httpProvider;
private readonly IHttpClient _httpClient;
private readonly IDroneServicesRequestBuilder _requestBuilder;
private readonly Logger _logger;
public DailySeriesDataProxy(IHttpProvider httpProvider, Logger logger)
public DailySeriesDataProxy(IHttpClient httpClient, IDroneServicesRequestBuilder requestBuilder, Logger logger)
{
_httpProvider = httpProvider;
_httpClient = httpClient;
_requestBuilder = requestBuilder;
_logger = logger;
}
@ -29,32 +29,15 @@ namespace NzbDrone.Core.DataAugmentation.DailySeries
{
try
{
var dailySeriesIds = _httpProvider.DownloadString(Services.RootUrl + "/v1/DailySeries");
var seriesIds = Json.Deserialize<List<int>>(dailySeriesIds);
return seriesIds;
var dailySeriesRequest = _requestBuilder.Build("dailyseries");
var response = _httpClient.Get<List<DailySeries>>(dailySeriesRequest);
return response.Resource.Select(c => c.TvdbId);
}
catch (Exception ex)
{
_logger.WarnException("Failed to get Daily Series", ex);
return new List<int>();
}
}
public bool IsDailySeries(int tvdbid)
{
try
{
var result = _httpProvider.DownloadString(Services.RootUrl + "/v1/DailySeries?seriesId=" + tvdbid);
return Convert.ToBoolean(result);
}
catch (Exception ex)
{
_logger.WarnException("Failed to check Daily Series status for: " + tvdbid, ex);
return false;
}
}
}
}

View File

@ -1,44 +1,30 @@
using NzbDrone.Core.Tv;
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Cache;
namespace NzbDrone.Core.DataAugmentation.DailySeries
{
public interface IDailySeriesService
{
void UpdateDailySeries();
bool IsDailySeries(int tvdbid);
}
public class DailySeriesService : IDailySeriesService
{
//TODO: add timer command
private readonly IDailySeriesDataProxy _proxy;
private readonly ISeriesService _seriesService;
private readonly ICached<List<int>> _cache;
public DailySeriesService(IDailySeriesDataProxy proxy, ISeriesService seriesService)
public DailySeriesService(IDailySeriesDataProxy proxy, ICacheManager cacheManager)
{
_proxy = proxy;
_seriesService = seriesService;
}
public void UpdateDailySeries()
{
var dailySeries = _proxy.GetDailySeriesIds();
foreach (var tvdbId in dailySeries)
{
var series = _seriesService.FindByTvdbId(tvdbId);
if (series != null)
{
_seriesService.SetSeriesType(series.Id, SeriesTypes.Daily);
}
}
_cache = cacheManager.GetCache<List<int>>(GetType());
}
public bool IsDailySeries(int tvdbid)
{
return _proxy.IsDailySeries(tvdbid);
var dailySeries = _cache.Get("all", () => _proxy.GetDailySeriesIds().ToList(), TimeSpan.FromHours(1));
return dailySeries.Any(i => i == tvdbid);
}
}
}

View File

@ -1,7 +1,6 @@
using System.Collections.Generic;
using NzbDrone.Common;
using NzbDrone.Common.Cloud;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
namespace NzbDrone.Core.DataAugmentation.Scene
{
@ -12,17 +11,19 @@ namespace NzbDrone.Core.DataAugmentation.Scene
public class SceneMappingProxy : ISceneMappingProxy
{
private readonly IHttpProvider _httpProvider;
private readonly IHttpClient _httpClient;
private readonly IDroneServicesRequestBuilder _requestBuilder;
public SceneMappingProxy(IHttpProvider httpProvider)
public SceneMappingProxy(IHttpClient httpClient, IDroneServicesRequestBuilder requestBuilder)
{
_httpProvider = httpProvider;
_httpClient = httpClient;
_requestBuilder = requestBuilder;
}
public List<SceneMapping> Fetch()
{
var mappingsJson = _httpProvider.DownloadString(Services.RootUrl + "/v1/SceneMapping");
return Json.Deserialize<List<SceneMapping>>(mappingsJson);
var request = _requestBuilder.Build("/scenemapping");
return _httpClient.Get<List<SceneMapping>>(request).Resource;
}
}
}

View File

@ -3,10 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.DataAugmentation.Xem.Model;
using NzbDrone.Core.Rest;
using RestSharp;
namespace NzbDrone.Core.DataAugmentation.Xem
{
@ -20,34 +19,32 @@ namespace NzbDrone.Core.DataAugmentation.Xem
public class XemProxy : IXemProxy
{
private readonly Logger _logger;
private readonly IHttpClient _httpClient;
private const string XEM_BASE_URL = "http://thexem.de/map/";
private static readonly string[] IgnoredErrors = { "no single connection", "no show with the tvdb_id" };
private HttpRequestBuilder _xemRequestBuilder;
public XemProxy(Logger logger)
public XemProxy(Logger logger, IHttpClient httpClient)
{
_logger = logger;
_httpClient = httpClient;
_xemRequestBuilder = new HttpRequestBuilder(XEM_BASE_URL)
{
PostProcess = r => r.UriBuilder.SetQueryParam("origin", "tvdb")
};
}
private static RestRequest BuildRequest(string resource)
{
var req = new RestRequest(resource, Method.GET);
req.AddParameter("origin", "tvdb");
return req;
}
public List<int> GetXemSeriesIds()
{
_logger.Debug("Fetching Series IDs from");
var restClient = RestClientFactory.BuildClient(XEM_BASE_URL);
var request = BuildRequest("havemap");
var response = restClient.ExecuteAndValidate<XemResult<List<int>>>(request);
var request = _xemRequestBuilder.Build("/havemap");
var response = _httpClient.Get<XemResult<List<int>>>(request).Resource;
CheckForFailureResult(response);
return response.Data.ToList();
@ -57,13 +54,11 @@ namespace NzbDrone.Core.DataAugmentation.Xem
{
_logger.Debug("Fetching Mappings for: {0}", id);
var restClient = RestClientFactory.BuildClient(XEM_BASE_URL);
var request = BuildRequest("all");
request.AddParameter("id", id);
var request = _xemRequestBuilder.Build("/all");
request.UriBuilder.SetQueryParam("id", id);
var response = restClient.ExecuteAndValidate<XemResult<List<XemSceneTvdbMapping>>>(request);
CheckForFailureResult(response);
var response = _httpClient.Get<XemResult<List<XemSceneTvdbMapping>>>(request).Resource;
return response.Data.Where(c => c.Scene != null).ToList();
}
@ -71,14 +66,11 @@ namespace NzbDrone.Core.DataAugmentation.Xem
public List<SceneMapping> GetSceneTvdbNames()
{
_logger.Debug("Fetching alternate names");
var restClient = RestClientFactory.BuildClient(XEM_BASE_URL);
var request = BuildRequest("allNames");
request.AddParameter("origin", "tvdb");
request.AddParameter("seasonNumbers", true);
var request = _xemRequestBuilder.Build("/allNames");
request.UriBuilder.SetQueryParam("seasonNumbers", true);
var response = restClient.ExecuteAndValidate<XemResult<Dictionary<Int32, List<JObject>>>>(request);
CheckForFailureResult(response);
var response = _httpClient.Get<XemResult<Dictionary<Int32, List<JObject>>>>(request).Resource;
var result = new List<SceneMapping>();

View File

@ -18,10 +18,10 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
public class Nzbget : DownloadClientBase<NzbgetSettings>
{
private readonly INzbgetProxy _proxy;
private readonly IHttpProvider _httpProvider;
private readonly IHttpClient _httpClient;
public Nzbget(INzbgetProxy proxy,
IHttpProvider httpProvider,
IHttpClient httpClient,
IConfigService configService,
IDiskProvider diskProvider,
IParsingService parsingService,
@ -29,7 +29,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
: base(configService, diskProvider, parsingService, logger)
{
_proxy = proxy;
_httpProvider = httpProvider;
_httpClient = httpClient;
}
public override DownloadProtocol Protocol
@ -49,7 +49,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
_logger.Info("Adding report [{0}] to the queue.", title);
using (var nzb = _httpProvider.DownloadStream(url))
using (var nzb = _httpClient.Get(new HttpRequest(url)).GetStream())
{
_logger.Info("Adding report [{0}] to the queue.", title);
var response = _proxy.DownloadNzb(nzb, title, category, priority, Settings);
@ -152,7 +152,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
}
var historyItems = new List<DownloadClientItem>();
var successStatus = new[] {"SUCCESS", "NONE"};
var successStatus = new[] { "SUCCESS", "NONE" };
foreach (var item in history)
{
@ -190,7 +190,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
public override IEnumerable<DownloadClientItem> GetItems()
{
Dictionary<String,String> config = null;
Dictionary<String, String> config = null;
NzbgetCategory category = null;
try
{

View File

@ -16,16 +16,16 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
{
public class Pneumatic : DownloadClientBase<PneumaticSettings>
{
private readonly IHttpProvider _httpProvider;
private readonly IHttpClient _httpClient;
public Pneumatic(IHttpProvider httpProvider,
public Pneumatic(IHttpClient httpClient,
IConfigService configService,
IDiskProvider diskProvider,
IParsingService parsingService,
Logger logger)
: base(configService, diskProvider, parsingService, logger)
{
_httpProvider = httpProvider;
_httpClient = httpClient;
}
public override DownloadProtocol Protocol
@ -52,7 +52,7 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
var nzbFile = Path.Combine(Settings.NzbFolder, title + ".nzb");
_logger.Debug("Downloading NZB from: {0} to: {1}", url, nzbFile);
_httpProvider.DownloadFile(url, nzbFile);
_httpClient.DownloadFile(url, nzbFile);
_logger.Debug("NZB Download succeeded, saved to: {0}", nzbFile);

View File

@ -18,11 +18,11 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
public class Sabnzbd : DownloadClientBase<SabnzbdSettings>
{
private readonly IHttpProvider _httpProvider;
private readonly ISabnzbdProxy _proxy;
private readonly IHttpClient _httpClient;
public Sabnzbd(ISabnzbdProxy proxy,
IHttpProvider httpProvider,
IHttpClient httpClient,
IConfigService configService,
IDiskProvider diskProvider,
IParsingService parsingService,
@ -30,7 +30,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
: base(configService, diskProvider, parsingService, logger)
{
_proxy = proxy;
_httpProvider = httpProvider;
_httpClient = httpClient;
}
public override DownloadProtocol Protocol
@ -48,7 +48,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
var category = Settings.TvCategory;
var priority = remoteEpisode.IsRecentEpisode() ? Settings.RecentTvPriority : Settings.OlderTvPriority;
using (var nzb = _httpProvider.DownloadStream(url))
using (var nzb = _httpClient.Get(new HttpRequest(url)).GetStream())
{
_logger.Info("Adding report [{0}] to the queue.", title);
var response = _proxy.DownloadNzb(nzb, title, category, priority, Settings);

View File

@ -19,10 +19,10 @@ namespace NzbDrone.Core.Download.Clients.UsenetBlackhole
public class UsenetBlackhole : DownloadClientBase<UsenetBlackholeSettings>
{
private readonly IDiskScanService _diskScanService;
private readonly IHttpProvider _httpProvider;
private readonly IHttpClient _httpClient;
public UsenetBlackhole(IDiskScanService diskScanService,
IHttpProvider httpProvider,
IHttpClient httpClient,
IConfigService configService,
IDiskProvider diskProvider,
IParsingService parsingService,
@ -30,7 +30,7 @@ namespace NzbDrone.Core.Download.Clients.UsenetBlackhole
: base(configService, diskProvider, parsingService, logger)
{
_diskScanService = diskScanService;
_httpProvider = httpProvider;
_httpClient = httpClient;
}
public override DownloadProtocol Protocol
@ -51,7 +51,7 @@ namespace NzbDrone.Core.Download.Clients.UsenetBlackhole
var filename = Path.Combine(Settings.NzbFolder, title + ".nzb");
_logger.Debug("Downloading NZB from: {0} to: {1}", url, filename);
_httpProvider.DownloadFile(url, filename);
_httpClient.DownloadFile(url, filename);
_logger.Debug("NZB Download succeeded, saved to: {0}", filename);
return null;

View File

@ -1,8 +1,5 @@
using NLog;
using NzbDrone.Common;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
namespace NzbDrone.Core.MediaCover
{
@ -14,14 +11,12 @@ namespace NzbDrone.Core.MediaCover
public class CoverAlreadyExistsSpecification : ICoverExistsSpecification
{
private readonly IDiskProvider _diskProvider;
private readonly IHttpProvider _httpProvider;
private readonly Logger _logger;
private readonly IHttpClient _httpClient;
public CoverAlreadyExistsSpecification(IDiskProvider diskProvider, IHttpProvider httpProvider, Logger logger)
public CoverAlreadyExistsSpecification(IDiskProvider diskProvider, IHttpClient httpClient)
{
_diskProvider = diskProvider;
_httpProvider = httpProvider;
_logger = logger;
_httpClient = httpClient;
}
public bool AlreadyExists(string url, string path)
@ -31,22 +26,9 @@ namespace NzbDrone.Core.MediaCover
return false;
}
var headers = _httpProvider.GetHeader(url);
string sizeString;
if (headers.TryGetValue(HttpProvider.CONTENT_LENGTH_HEADER, out sizeString))
{
int size;
int.TryParse(sizeString, out size);
var fileSize = _diskProvider.GetFileSize(path);
return fileSize == size;
}
_logger.Warn("Couldn't find content-length header {0}", headers.ToJson());
return false;
var headers = _httpClient.Head(new HttpRequest(url)).Headers;
var fileSize = _diskProvider.GetFileSize(path);
return fileSize == headers.ContentLength;
}
}
}

View File

@ -25,7 +25,7 @@ namespace NzbDrone.Core.MediaCover
IHandleAsync<SeriesDeletedEvent>,
IMapCoversToLocal
{
private readonly IHttpProvider _httpProvider;
private readonly IHttpClient _httpClient;
private readonly IDiskProvider _diskProvider;
private readonly ICoverExistsSpecification _coverExistsSpecification;
private readonly IConfigFileProvider _configFileProvider;
@ -34,7 +34,7 @@ namespace NzbDrone.Core.MediaCover
private readonly string _coverRootFolder;
public MediaCoverService(IHttpProvider httpProvider,
public MediaCoverService(IHttpClient httpClient,
IDiskProvider diskProvider,
IAppFolderInfo appFolderInfo,
ICoverExistsSpecification coverExistsSpecification,
@ -42,7 +42,7 @@ namespace NzbDrone.Core.MediaCover
IEventAggregator eventAggregator,
Logger logger)
{
_httpProvider = httpProvider;
_httpClient = httpClient;
_diskProvider = diskProvider;
_coverExistsSpecification = coverExistsSpecification;
_configFileProvider = configFileProvider;
@ -106,7 +106,7 @@ namespace NzbDrone.Core.MediaCover
var fileName = GetCoverPath(series.Id, cover.CoverType);
_logger.Info("Downloading {0} for {1} {2}", cover.CoverType, series, cover.Url);
_httpProvider.DownloadFile(cover.Url, fileName);
_httpClient.DownloadFile(cover.Url, fileName);
}
public void HandleAsync(SeriesUpdatedEvent message)

View File

@ -29,7 +29,7 @@ namespace NzbDrone.Core.Metadata
private readonly IMediaFileService _mediaFileService;
private readonly IEpisodeService _episodeService;
private readonly IDiskProvider _diskProvider;
private readonly IHttpProvider _httpProvider;
private readonly IHttpClient _httpClient;
private readonly IConfigService _configService;
private readonly IEventAggregator _eventAggregator;
private readonly Logger _logger;
@ -40,7 +40,7 @@ namespace NzbDrone.Core.Metadata
IMediaFileService mediaFileService,
IEpisodeService episodeService,
IDiskProvider diskProvider,
IHttpProvider httpProvider,
IHttpClient httpClient,
IConfigService configService,
IEventAggregator eventAggregator,
Logger logger)
@ -51,7 +51,7 @@ namespace NzbDrone.Core.Metadata
_mediaFileService = mediaFileService;
_episodeService = episodeService;
_diskProvider = diskProvider;
_httpProvider = httpProvider;
_httpClient = httpClient;
_configService = configService;
_eventAggregator = eventAggregator;
_logger = logger;
@ -336,7 +336,7 @@ namespace NzbDrone.Core.Metadata
{
try
{
_httpProvider.DownloadFile(url, path);
_httpClient.DownloadFile(url, path);
SetFilePermissions(path);
}
catch (WebException e)

View File

@ -2,86 +2,93 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Web;
using NLog;
using NzbDrone.Common;
using NzbDrone.Common.Http;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource.Trakt;
using NzbDrone.Core.Tv;
using RestSharp;
using Episode = NzbDrone.Core.Tv.Episode;
using NzbDrone.Core.Rest;
namespace NzbDrone.Core.MetadataSource
{
public class TraktProxy : ISearchForNewSeries, IProvideSeriesInfo
{
private readonly Logger _logger;
private readonly IHttpClient _httpClient;
private static readonly Regex CollapseSpaceRegex = new Regex(@"\s+", RegexOptions.Compiled);
private static readonly Regex InvalidSearchCharRegex = new Regex(@"(?:\*|\(|\)|'|!|@|\+)", RegexOptions.Compiled);
public TraktProxy(Logger logger)
private readonly HttpRequestBuilder _requestBuilder;
public TraktProxy(Logger logger, IHttpClient httpClient)
{
_requestBuilder = new HttpRequestBuilder("http://api.trakt.tv/{path}/{resource}.json/bc3c2c460f22cbb01c264022b540e191");
_logger = logger;
_httpClient = httpClient;
}
private IEnumerable<Show> SearchTrakt(string title)
{
HttpRequest request;
var lowerTitle = title.ToLowerInvariant();
if (lowerTitle.StartsWith("tvdb:") || lowerTitle.StartsWith("tvdbid:") || lowerTitle.StartsWith("slug:"))
{
var slug = lowerTitle.Split(':')[1].Trim();
if (slug.IsNullOrWhiteSpace() || slug.Any(char.IsWhiteSpace))
{
return Enumerable.Empty<Show>();
}
request = _requestBuilder.Build("/{slug}/extended");
request.AddSegment("path", "show");
request.AddSegment("resource", "summary");
request.AddSegment("slug", GetSearchTerm(slug));
return new List<Show> { _httpClient.Get<Show>(request).Resource };
}
if (lowerTitle.StartsWith("imdb:") || lowerTitle.StartsWith("imdbid:"))
{
var slug = lowerTitle.Split(':')[1].TrimStart('t').Trim();
if (slug.IsNullOrWhiteSpace() || !slug.All(char.IsDigit) || slug.Length < 7)
{
return Enumerable.Empty<Show>();
}
title = "tt" + slug;
}
request = _requestBuilder.Build("");
request.AddSegment("path", "search");
request.AddSegment("resource", "shows");
request.UriBuilder.SetQueryParam("query", GetSearchTerm(title));
request.UriBuilder.SetQueryParam("seasons", true);
return _httpClient.Get<List<Show>>(request).Resource;
}
public List<Series> SearchForNewSeries(string title)
{
try
{
if (title.StartsWith("imdb:") || title.StartsWith("imdbid:"))
{
var slug = title.Split(':')[1].TrimStart('t');
var series = SearchTrakt(title.Trim());
if (slug.IsNullOrWhiteSpace() || !slug.All(char.IsDigit) || slug.Length < 7)
{
return new List<Series>();
}
title = "tt" + slug;
}
if (title.StartsWith("tvdb:") || title.StartsWith("tvdbid:") || title.StartsWith("slug:"))
{
try
{
var slug = title.Split(':')[1];
if (slug.IsNullOrWhiteSpace() || slug.Any(char.IsWhiteSpace))
{
return new List<Series>();
}
var client = BuildClient("show", "summary");
var restRequest = new RestRequest(GetSearchTerm(slug) + "/extended");
var response = client.ExecuteAndValidate<Show>(restRequest);
return new List<Series> { MapSeries(response) };
}
catch (RestException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.NotFound)
{
return new List<Series>();
}
throw;
}
}
else
{
var client = BuildClient("search", "shows");
var restRequest = new RestRequest(GetSearchTerm(title) + "/30/seasons");
var response = client.ExecuteAndValidate<List<Show>>(restRequest);
return response.Select(MapSeries)
.OrderBy(v => title.LevenshteinDistanceClean(v.Title))
.ToList();
}
return series.Select(MapSeries)
.OrderBy(s => title.LevenshteinDistanceClean(s.Title))
.ToList();
}
catch (WebException)
catch (HttpException)
{
throw new TraktException("Search for '{0}' failed. Unable to communicate with Trakt.", title);
}
@ -94,20 +101,31 @@ namespace NzbDrone.Core.MetadataSource
public Tuple<Series, List<Episode>> GetSeriesInfo(int tvdbSeriesId)
{
var client = BuildClient("show", "summary");
var restRequest = new RestRequest(tvdbSeriesId.ToString() + "/extended");
var response = client.ExecuteAndValidate<Show>(restRequest);
var request = _requestBuilder.Build("/{tvdbId}/extended");
request.AddSegment("path", "show");
request.AddSegment("resource", "summary");
request.AddSegment("tvdbId", tvdbSeriesId.ToString());
var response = _httpClient.Get<Show>(request).Resource;
/*
var client = BuildClient("show", "summary");
var restRequest = new RestRequest(tvdbSeriesId + "/extended");
var response = client.ExecuteAndValidate<Show>(restRequest);*/
var episodes = response.seasons.SelectMany(c => c.episodes).Select(MapEpisode).ToList();
var series = MapSeries(response);
return new Tuple<Series, List<Episode>>(series, episodes);
}
private static IRestClient BuildClient(string resource, string method)
{
return RestClientFactory.BuildClient(string.Format("http://api.trakt.tv/{0}/{1}.json/bc3c2c460f22cbb01c264022b540e191", resource, method));
}
/*
private static IRestClient BuildClient(string resource, string method)
{
return RestClientFactory.BuildClient(string.Format("http://api.trakt.tv/{0}/{1}.json/bc3c2c460f22cbb01c264022b540e191", resource, method));
}*/
private static Series MapSeries(Show show)
{
@ -139,6 +157,18 @@ namespace NzbDrone.Core.MetadataSource
return series;
}
private static String GetTitleSlug(String url)
{
var slug = url.ToLower().Replace("http://trakt.tv/show/", "");
if (slug.StartsWith("."))
{
slug = "dot" + slug.Substring(1);
}
return slug;
}
private static Episode MapEpisode(Trakt.Episode traktEpisode)
{
var episode = new Episode();
@ -179,13 +209,6 @@ namespace NzbDrone.Core.MetadataSource
return SeriesStatusType.Continuing;
}
private static DateTime? FromEpoch(long ticks)
{
if (ticks == 0) return null;
return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified).AddSeconds(ticks);
}
private static DateTime? FromIso(string iso)
{
DateTime result;
@ -213,7 +236,7 @@ namespace NzbDrone.Core.MetadataSource
phrase = InvalidSearchCharRegex.Replace(phrase, "");
phrase = CollapseSpaceRegex.Replace(phrase, " ").Trim().ToLower();
phrase = phrase.Trim('-');
phrase = HttpUtility.UrlEncode(phrase);
phrase = System.Web.HttpUtility.UrlEncode(phrase);
return phrase;
}
@ -286,16 +309,6 @@ namespace NzbDrone.Core.MetadataSource
return seasons;
}
private static String GetTitleSlug(String url)
{
var slug = url.ToLower().Replace("http://trakt.tv/show/", "");
if (slug.StartsWith("."))
{
slug = "dot" + slug.Substring(1);
}
return slug;
}
}
}

View File

@ -1,12 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using NzbDrone.Core.Rest;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Tv;
using RestSharp;
namespace NzbDrone.Core.MetadataSource.Tvdb
{
@ -17,37 +15,22 @@ namespace NzbDrone.Core.MetadataSource.Tvdb
public class TvdbProxy : ITvdbProxy
{
public Tuple<Series, List<Episode>> GetSeriesInfo(int tvdbSeriesId)
private readonly IHttpClient _httpClient;
public TvdbProxy(IHttpClient httpClient)
{
var client = BuildClient("series");
var request = new RestRequest(tvdbSeriesId + "/all");
var response = client.Execute(request);
var xml = XDocument.Load(new StringReader(response.Content));
var episodes = xml.Descendants("Episode").Select(MapEpisode).ToList();
var series = MapSeries(xml.Element("Series"));
return new Tuple<Series, List<Episode>>(series, episodes);
_httpClient = httpClient;
}
public List<Episode> GetEpisodeInfo(int tvdbSeriesId)
{
return GetSeriesInfo(tvdbSeriesId).Item2;
}
var httpRequest = new HttpRequest("http://thetvdb.com/data/series/{tvdbId}/all/");
httpRequest.AddSegment("tvdbId", tvdbSeriesId.ToString());
var response = _httpClient.Get(httpRequest);
private static IRestClient BuildClient(string resource)
{
return RestClientFactory.BuildClient(String.Format("http://thetvdb.com/data/{0}", resource));
}
private static Series MapSeries(XElement item)
{
//TODO: We should map all the data incase we want to actually use it
var series = new Series();
return series;
var xml = XDocument.Load(new StringReader(response.Content));
var episodes = xml.Descendants("Episode").Select(MapEpisode).ToList();
return episodes;
}
private static Episode MapEpisode(XElement item)

View File

@ -128,6 +128,7 @@
<Compile Include="Configuration\IConfigService.cs" />
<Compile Include="Configuration\InvalidConfigFileException.cs" />
<Compile Include="Configuration\ResetApiKeyCommand.cs" />
<Compile Include="DataAugmentation\DailySeries\DailySeries.cs" />
<Compile Include="DataAugmentation\DailySeries\DailySeriesDataProxy.cs" />
<Compile Include="DataAugmentation\DailySeries\DailySeriesService.cs" />
<Compile Include="DataAugmentation\Scene\ISceneMappingProvider.cs" />

View File

@ -26,7 +26,7 @@ namespace NzbDrone.Core.Update
private readonly IAppFolderInfo _appFolderInfo;
private readonly IDiskProvider _diskProvider;
private readonly IHttpProvider _httpProvider;
private readonly IHttpClient _httpClient;
private readonly IArchiveService _archiveService;
private readonly IProcessProvider _processProvider;
private readonly IVerifyUpdates _updateVerifier;
@ -36,7 +36,7 @@ namespace NzbDrone.Core.Update
public InstallUpdateService(ICheckUpdateService checkUpdateService, IAppFolderInfo appFolderInfo,
IDiskProvider diskProvider, IHttpProvider httpProvider,
IDiskProvider diskProvider, IHttpClient httpClient,
IArchiveService archiveService, IProcessProvider processProvider,
IVerifyUpdates updateVerifier,
IConfigFileProvider configFileProvider,
@ -51,7 +51,7 @@ namespace NzbDrone.Core.Update
_checkUpdateService = checkUpdateService;
_appFolderInfo = appFolderInfo;
_diskProvider = diskProvider;
_httpProvider = httpProvider;
_httpClient = httpClient;
_archiveService = archiveService;
_processProvider = processProvider;
_updateVerifier = updateVerifier;
@ -79,7 +79,7 @@ namespace NzbDrone.Core.Update
_logger.ProgressInfo("Downloading update {0}", updatePackage.Version);
_logger.Debug("Downloading update package from [{0}] to [{1}]", updatePackage.Url, packageDestination);
_httpProvider.DownloadFile(updatePackage.Url, packageDestination);
_httpClient.DownloadFile(updatePackage.Url, packageDestination);
_logger.ProgressInfo("Verifying update package");

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Core.Update
@ -23,7 +24,7 @@ namespace NzbDrone.Core.Update
public List<UpdatePackage> GetRecentUpdatePackages()
{
var branch = _configFileProvider.Branch;
return _updatePackageProvider.GetRecentUpdates(branch);
return _updatePackageProvider.GetRecentUpdates(branch, BuildInfo.Version.Major);
}
}
}

View File

@ -6,7 +6,6 @@ namespace NzbDrone.Core.Update
public class UpdatePackage
{
public Version Version { get; set; }
public String Branch { get; set; }
public DateTime ReleaseDate { get; set; }
public String FileName { get; set; }
public String Url { get; set; }

View File

@ -1,50 +1,51 @@
using System;
using System.Collections.Generic;
using NzbDrone.Common;
using NzbDrone.Common.Cloud;
using NzbDrone.Common.EnvironmentInfo;
using RestSharp;
using NzbDrone.Core.Rest;
using NzbDrone.Common.Http;
namespace NzbDrone.Core.Update
{
public interface IUpdatePackageProvider
{
UpdatePackage GetLatestUpdate(string branch, Version currentVersion);
List<UpdatePackage> GetRecentUpdates(string branch);
List<UpdatePackage> GetRecentUpdates(string branch, int majorVersion);
}
public class UpdatePackageProvider : IUpdatePackageProvider
{
private readonly IHttpClient _httpClient;
private readonly IDroneServicesRequestBuilder _requestBuilder;
public UpdatePackageProvider(IHttpClient httpClient, IDroneServicesRequestBuilder requestBuilder)
{
_httpClient = httpClient;
_requestBuilder = requestBuilder;
}
public UpdatePackage GetLatestUpdate(string branch, Version currentVersion)
{
var restClient = RestClientFactory.BuildClient(Services.RootUrl);
var request = _requestBuilder.Build("/update/{branch}");
request.UriBuilder.SetQueryParam("version", currentVersion);
request.UriBuilder.SetQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant());
request.AddSegment("branch", branch);
var request = new RestRequest("/v1/update/{branch}");
request.AddParameter("version", currentVersion);
request.AddParameter("os", OsInfo.Os.ToString().ToLowerInvariant());
request.AddUrlSegment("branch", branch);
var update = restClient.ExecuteAndValidate<UpdatePackageAvailable>(request);
var update = _httpClient.Get<UpdatePackageAvailable>(request).Resource;
if (!update.Available) return null;
return update.UpdatePackage;
}
public List<UpdatePackage> GetRecentUpdates(string branch)
public List<UpdatePackage> GetRecentUpdates(string branch, int majorVersion)
{
var restClient = RestClientFactory.BuildClient(Services.RootUrl);
var request = _requestBuilder.Build("/update/{branch}/changes");
request.UriBuilder.SetQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant());
request.AddSegment("branch", branch);
var request = new RestRequest("/v1/update/{branch}/changes");
var updates = _httpClient.Get<List<UpdatePackage>>(request);
request.AddParameter("majorVersion", BuildInfo.Version.Major);
request.AddParameter("os", OsInfo.Os.ToString().ToLowerInvariant());
request.AddUrlSegment("branch", branch);
var updates = restClient.ExecuteAndValidate<List<UpdatePackage>>(request);
return updates;
return updates.Resource;
}
}
}

View File

@ -8,14 +8,12 @@ namespace NzbDrone.Test.Common
{
public abstract class LoggingTest
{
protected static Logger TestLogger;
protected static readonly Logger TestLogger = LogManager.GetLogger("TestLogger");
protected static void InitLogging()
{
new StartupContext();
TestLogger = LogManager.GetLogger("TestLogger");
if (LogManager.Configuration == null || LogManager.Configuration is XmlLoggingConfiguration)
{
LogManager.Configuration = new LoggingConfiguration();
@ -44,8 +42,6 @@ namespace NzbDrone.Test.Common
[TearDown]
public void LoggingDownBase()
{
//can't use because of a bug in mono with 2.6.2,
//https://bugs.launchpad.net/nunitv2/+bug/1076932
if (BuildInfo.IsDebug && TestContext.CurrentContext.Result.State == TestState.Success)

View File

@ -54,6 +54,9 @@ namespace NzbDrone.Test.Common
if (_mocker == null)
{
_mocker = new AutoMoqer();
_mocker.SetConstant<ICacheManager>(new CacheManager());
_mocker.SetConstant<IStartupContext>(new StartupContext(new string[0]));
_mocker.SetConstant(TestLogger);
}
return _mocker;
@ -89,11 +92,7 @@ namespace NzbDrone.Test.Common
GetType().IsPublic.Should().BeTrue("All Test fixtures should be public to work in mono.");
Mocker.SetConstant<ICacheManager>(new CacheManager());
Mocker.SetConstant(LogManager.GetLogger("TestLogger"));
Mocker.SetConstant<IStartupContext>(new StartupContext(new string[0]));
LogManager.ReconfigExistingLoggers();
@ -140,7 +139,7 @@ namespace NzbDrone.Test.Common
{
if (!OsInfo.IsMono)
{
throw new IgnoreException("linux specific test");
throw new IgnoreException("mono specific test");
}
}