added RestSharpExtensions to help validate REST response

This commit is contained in:
kay.one 2013-08-17 17:17:37 -07:00
parent e7805a5afb
commit 9c8c485c98
9 changed files with 126 additions and 39 deletions

View File

@ -4,6 +4,7 @@ using System.Linq;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.MetadataSource; using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.Rest;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Test.Common.Categories; using NzbDrone.Test.Common.Categories;
@ -45,6 +46,13 @@ namespace NzbDrone.Core.Test.MetadataSourceTests
ValidateEpisodes(details.Item2); ValidateEpisodes(details.Item2);
} }
[Test]
public void getting_details_of_invalid_series()
{
Assert.Throws<RestException>(() => Subject.GetSeriesInfo(Int32.MaxValue));
}
private void ValidateSeries(Series series) private void ValidateSeries(Series series)
{ {
series.Should().NotBeNull(); series.Should().NotBeNull();

View File

@ -10,6 +10,7 @@ using NzbDrone.Core.MetadataSource.Trakt;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using RestSharp; using RestSharp;
using Episode = NzbDrone.Core.Tv.Episode; using Episode = NzbDrone.Core.Tv.Episode;
using NzbDrone.Core.Rest;
namespace NzbDrone.Core.MetadataSource namespace NzbDrone.Core.MetadataSource
{ {
@ -19,23 +20,20 @@ namespace NzbDrone.Core.MetadataSource
{ {
var client = BuildClient("search", "shows"); var client = BuildClient("search", "shows");
var restRequest = new RestRequest(title.ToSearchTerm()); var restRequest = new RestRequest(title.ToSearchTerm());
var response = client.Execute<List<Show>>(restRequest); var response = client.ExecuteAndValidate<List<Show>>(restRequest);
CheckForError(response); return response.Select(MapSeries).ToList();
return response.Data.Select(MapSeries).ToList();
} }
public Tuple<Series, List<Episode>> GetSeriesInfo(int tvDbSeriesId) public Tuple<Series, List<Episode>> GetSeriesInfo(int tvDbSeriesId)
{ {
var client = BuildClient("show", "summary"); var client = BuildClient("show", "summary");
var restRequest = new RestRequest(tvDbSeriesId.ToString() + "/extended"); var restRequest = new RestRequest(tvDbSeriesId.ToString() + "/extended");
var response = client.Execute<Show>(restRequest); var response = client.ExecuteAndValidate<Show>(restRequest);
CheckForError(response);
var episodes = response.Data.seasons.SelectMany(c => c.episodes).Select(MapEpisode).ToList(); var episodes = response.seasons.SelectMany(c => c.episodes).Select(MapEpisode).ToList();
var series = MapSeries(response.Data); var series = MapSeries(response);
return new Tuple<Series, List<Episode>>(series, episodes); return new Tuple<Series, List<Episode>>(series, episodes);
} }
@ -126,12 +124,6 @@ namespace NzbDrone.Core.MetadataSource
return match.Captures[0].Value; return match.Captures[0].Value;
} }
private void CheckForError(IRestResponse response)
{
if (response.StatusCode != HttpStatusCode.OK)
{
throw new TraktCommunicationException(response.ErrorMessage, response.ErrorException);
}
}
} }
} }

View File

@ -4,11 +4,11 @@ namespace NzbDrone.Core.Notifications.Pushover
{ {
public class Pushover : NotificationBase<PushoverSettings> public class Pushover : NotificationBase<PushoverSettings>
{ {
private readonly IPushoverService _pushoverService; private readonly IPushoverProxy _pushoverProxy;
public Pushover(IPushoverService pushoverService) public Pushover(IPushoverProxy pushoverProxy)
{ {
_pushoverService = pushoverService; _pushoverProxy = pushoverProxy;
} }
public override string Name public override string Name
@ -30,14 +30,14 @@ namespace NzbDrone.Core.Notifications.Pushover
{ {
const string title = "Episode Grabbed"; const string title = "Episode Grabbed";
_pushoverService.SendNotification(title, message, Settings.UserKey, (PushoverPriority)Settings.Priority); _pushoverProxy.SendNotification(title, message, Settings.UserKey, (PushoverPriority)Settings.Priority);
} }
public override void OnDownload(string message, Series series) public override void OnDownload(string message, Series series)
{ {
const string title = "Episode Downloaded"; const string title = "Episode Downloaded";
_pushoverService.SendNotification(title, message, Settings.UserKey, (PushoverPriority)Settings.Priority); _pushoverProxy.SendNotification(title, message, Settings.UserKey, (PushoverPriority)Settings.Priority);
} }
public override void AfterRename(Series series) public override void AfterRename(Series series)

View File

@ -1,27 +1,19 @@
using System.Net; using NzbDrone.Common.Messaging;
using NLog;
using NzbDrone.Common.Messaging;
using RestSharp; using RestSharp;
using NzbDrone.Core.Rest;
namespace NzbDrone.Core.Notifications.Pushover namespace NzbDrone.Core.Notifications.Pushover
{ {
public interface IPushoverService public interface IPushoverProxy
{ {
void SendNotification(string title, string message, string userKey, PushoverPriority priority); void SendNotification(string title, string message, string userKey, PushoverPriority priority);
} }
public class PushoverService : IPushoverService, IExecute<TestPushoverCommand> public class PushoverProxy : IPushoverProxy, IExecute<TestPushoverCommand>
{ {
private readonly Logger _logger;
private const string TOKEN = "yz9b4U215iR4vrKFRfjNXP24NMNPKJ"; private const string TOKEN = "yz9b4U215iR4vrKFRfjNXP24NMNPKJ";
private const string URL = "https://api.pushover.net/1/messages.json"; private const string URL = "https://api.pushover.net/1/messages.json";
public PushoverService(Logger logger)
{
_logger = logger;
}
public void SendNotification(string title, string message, string userKey, PushoverPriority priority) public void SendNotification(string title, string message, string userKey, PushoverPriority priority)
{ {
var client = new RestClient(URL); var client = new RestClient(URL);
@ -32,12 +24,7 @@ namespace NzbDrone.Core.Notifications.Pushover
request.AddParameter("message", message); request.AddParameter("message", message);
request.AddParameter("priority", (int)priority); request.AddParameter("priority", (int)priority);
var response = client.Execute(request); client.ExecuteAndValidate(request);
if (response.StatusCode != HttpStatusCode.OK)
{
throw new InvalidResponseException(response.Content);
}
} }
public void Execute(TestPushoverCommand message) public void Execute(TestPushoverCommand message)

View File

@ -342,6 +342,8 @@
<Compile Include="Qualities\QualityProfileInUseException.cs" /> <Compile Include="Qualities\QualityProfileInUseException.cs" />
<Compile Include="Qualities\QualitySizeRepository.cs" /> <Compile Include="Qualities\QualitySizeRepository.cs" />
<Compile Include="Qualities\QualityProfileRepository.cs" /> <Compile Include="Qualities\QualityProfileRepository.cs" />
<Compile Include="Rest\RestSharpExtensions.cs" />
<Compile Include="Rest\RestException.cs" />
<Compile Include="SeriesStats\SeriesStatisticsService.cs" /> <Compile Include="SeriesStats\SeriesStatisticsService.cs" />
<Compile Include="Tv\EpisodeService.cs" /> <Compile Include="Tv\EpisodeService.cs" />
<Compile Include="Tv\Events\EpisodeInfoUpdatedEvent.cs" /> <Compile Include="Tv\Events\EpisodeInfoUpdatedEvent.cs" />
@ -541,6 +543,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Download\Clients\Sabnzbd\Api\" /> <Folder Include="Download\Clients\Sabnzbd\Api\" />
<Folder Include="Download\Clients\uTorrent\" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>

View File

@ -0,0 +1,26 @@
using System;
using RestSharp;
namespace NzbDrone.Core.Rest
{
public class RestException : Exception
{
public IRestResponse Response { get; private set; }
public RestException(IRestResponse response, IRestClient restClient)
: base(string.Format("REST request failed: [{0}] [{1}] at [{2}]", (int)response.StatusCode, response.Request.Method, restClient.BuildUri(response.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.Net;
using NLog;
using NzbDrone.Common.EnsureThat;
using NzbDrone.Common.Serializer;
using RestSharp;
namespace NzbDrone.Core.Rest
{
public static class RestSharpExtensions
{
private static readonly Logger Logger = LogManager.GetLogger("RestExtensions");
public static IRestResponse ValidateResponse(this IRestResponse response, IRestClient restClient)
{
Ensure.That(() => response).IsNotNull();
if (response.Request == null && response.ErrorException != null)
{
throw response.ErrorException;
}
Ensure.That(() => response.Request).IsNotNull();
Ensure.That(() => restClient).IsNotNull();
Logger.Debug("Validating Responses from [{0}] [{1}] status: [{2}] body:[{3}]", response.Request.Method, restClient.BuildUri(response.Request), response.StatusCode, response.Content);
if (response.ResponseUri == null)
{
Logger.ErrorException("Error communicating with server", response.ErrorException);
throw response.ErrorException;
}
switch (response.StatusCode)
{
case HttpStatusCode.OK:
{
return response;
}
default:
{
Logger.Warn("[{0}] [{1}] Failed. [{2}]", response.Request.Method, response.ResponseUri.ToString(), response.StatusCode);
throw new RestException(response, restClient);
}
}
}
public static T Read<T>(this IRestResponse restResponse, IRestClient restClient) where T : class, new()
{
restResponse.ValidateResponse(restClient);
return Json.Deserialize<T>(restResponse.Content);
}
public static T ExecuteAndValidate<T>(this IRestClient client, IRestRequest request) where T : class, new()
{
return client.Execute(request).Read<T>(client);
}
public static IRestResponse ExecuteAndValidate(this IRestClient client, IRestRequest request)
{
return client.Execute(request).ValidateResponse(client);
}
public static void AddQueryString(this IRestRequest request, string name, object value)
{
request.AddParameter(name, value.ToString(), ParameterType.GetOrPost);
}
}
}

View File

@ -48,7 +48,7 @@ namespace NzbDrone.Test.Common
//can't use because of a bug in mono with 2.6.2, //can't use because of a bug in mono with 2.6.2,
//https://bugs.launchpad.net/nunitv2/+bug/1076932 //https://bugs.launchpad.net/nunitv2/+bug/1076932
//if (TestContext.CurrentContext.Result.State == TestState.Success) if (OsInfo.IsWindows && TestContext.CurrentContext.Result.State == TestState.Success)
{ {
ExceptionVerification.AssertNoUnexcpectedLogs(); ExceptionVerification.AssertNoUnexcpectedLogs();
} }

View File

@ -8,6 +8,7 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=InvokeAsExtensionMethod/@EntryIndexedValue">ERROR</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=InvokeAsExtensionMethod/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=NUnit_002ENonPublicMethodWithTestAttribute/@EntryIndexedValue">ERROR</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=NUnit_002ENonPublicMethodWithTestAttribute/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReturnTypeCanBeEnumerable_002EGlobal/@EntryIndexedValue">HINT</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReturnTypeCanBeEnumerable_002EGlobal/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseObjectOrCollectionInitializer/@EntryIndexedValue">HINT</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseObjectOrCollectionInitializer/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=NzbDrone/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="NzbDrone"&gt;&lt;CSArrangeThisQualifier&gt;True&lt;/CSArrangeThisQualifier&gt;&lt;RemoveCodeRedundancies&gt;True&lt;/RemoveCodeRedundancies&gt;&lt;CSUseAutoProperty&gt;True&lt;/CSUseAutoProperty&gt;&lt;CSMakeFieldReadonly&gt;True&lt;/CSMakeFieldReadonly&gt;&lt;CSUseVar&gt;&lt;BehavourStyle&gt;CAN_CHANGE_TO_IMPLICIT&lt;/BehavourStyle&gt;&lt;LocalVariableStyle&gt;IMPLICIT_EXCEPT_SIMPLE_TYPES&lt;/LocalVariableStyle&gt;&lt;ForeachVariableStyle&gt;ALWAYS_IMPLICIT&lt;/ForeachVariableStyle&gt;&lt;/CSUseVar&gt;&lt;CSUpdateFileHeader&gt;True&lt;/CSUpdateFileHeader&gt;&lt;CSOptimizeUsings&gt;&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;&lt;EmbraceInRegion&gt;False&lt;/EmbraceInRegion&gt;&lt;RegionName&gt;&lt;/RegionName&gt;&lt;/CSOptimizeUsings&gt;&lt;CSShortenReferences&gt;True&lt;/CSShortenReferences&gt;&lt;CSReorderTypeMembers&gt;True&lt;/CSReorderTypeMembers&gt;&lt;XAMLCollapseEmptyTags&gt;False&lt;/XAMLCollapseEmptyTags&gt;&lt;/Profile&gt;</s:String> <s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=NzbDrone/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="NzbDrone"&gt;&lt;CSArrangeThisQualifier&gt;True&lt;/CSArrangeThisQualifier&gt;&lt;RemoveCodeRedundancies&gt;True&lt;/RemoveCodeRedundancies&gt;&lt;CSUseAutoProperty&gt;True&lt;/CSUseAutoProperty&gt;&lt;CSMakeFieldReadonly&gt;True&lt;/CSMakeFieldReadonly&gt;&lt;CSUseVar&gt;&lt;BehavourStyle&gt;CAN_CHANGE_TO_IMPLICIT&lt;/BehavourStyle&gt;&lt;LocalVariableStyle&gt;IMPLICIT_EXCEPT_SIMPLE_TYPES&lt;/LocalVariableStyle&gt;&lt;ForeachVariableStyle&gt;ALWAYS_IMPLICIT&lt;/ForeachVariableStyle&gt;&lt;/CSUseVar&gt;&lt;CSUpdateFileHeader&gt;True&lt;/CSUpdateFileHeader&gt;&lt;CSOptimizeUsings&gt;&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;&lt;EmbraceInRegion&gt;False&lt;/EmbraceInRegion&gt;&lt;RegionName&gt;&lt;/RegionName&gt;&lt;/CSOptimizeUsings&gt;&lt;CSShortenReferences&gt;True&lt;/CSShortenReferences&gt;&lt;CSReorderTypeMembers&gt;True&lt;/CSReorderTypeMembers&gt;&lt;XAMLCollapseEmptyTags&gt;False&lt;/XAMLCollapseEmptyTags&gt;&lt;/Profile&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/SilentCleanupProfile/@EntryValue">NzbDrone</s:String> <s:String x:Key="/Default/CodeStyle/CodeCleanup/SilentCleanupProfile/@EntryValue">NzbDrone</s:String>