Skip to content

Commit

Permalink
Merge pull request #12 from JSkimming/error-handling
Browse files Browse the repository at this point in the history
Add request error tests
  • Loading branch information
JSkimming committed Aug 26, 2015
2 parents ecfcfbc + 7d2cf6e commit c29a99a
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 17 deletions.
1 change: 1 addition & 0 deletions src/CloudFlare.NET/CloudFlare.NET.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
<Compile Include="CloudFlareClient.cs" />
<Compile Include="CloudFlareConstants.cs" />
<Compile Include="CloudFlareError.cs" />
<Compile Include="CloudFlareException.cs" />
<Compile Include="CloudFlareResponse.cs" />
<Compile Include="CloudFlareResponseBase.cs" />
<Compile Include="CloudFlareResultInfo.cs" />
Expand Down
62 changes: 62 additions & 0 deletions src/CloudFlare.NET/CloudFlareException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
namespace CloudFlare.NET
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;

/// <summary>
/// Contains the erred <see cref="CloudFlareResponseBase"/> to a request.
/// </summary>
public class CloudFlareException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="CloudFlareException"/> class.
/// </summary>
public CloudFlareException(
CloudFlareResponseBase response,
HttpResponseMessage httpResponse = null,
Exception innerException = null)
: base(GetMessage(response, httpResponse), innerException)
{
Response = response;
SetupData(response);
}

/// <summary>
/// Gets the error information of the response.
/// </summary>
public CloudFlareResponseBase Response { get; }

private static string GetMessage(CloudFlareResponseBase response, HttpResponseMessage httpResponse = null)
{
if (response == null)
throw new ArgumentNullException(nameof(response));

string message = response.Errors.FirstOrDefault()?.Message ?? "Unknown error.";
string requestMethod = httpResponse?.RequestMessage?.Method?.ToString() ?? "Unknown HTTP Method";
string requestUri = httpResponse?.RequestMessage?.RequestUri?.AbsoluteUri ?? "Unknown Uri";

return $"{message}: {requestMethod} {requestUri}";
}

private void SetupData(CloudFlareResponseBase response)
{
if (response == null)
throw new ArgumentNullException(nameof(response));

int index = 1;
foreach (CloudFlareError error in response.Errors)
{
Data[$"ErrorCode{index}"] = error.Code;
Data[$"ErrorMessage{index}"] = error.Message;
}

index = 1;
foreach (string message in response.Messages)
{
Data[$"Message{index}"] = message;
}
}
}
}
14 changes: 7 additions & 7 deletions src/CloudFlare.NET/HttpClientExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static class HttpClientExtensions
public static Uri ZonesUri { get; } = new Uri(CloudFlareConstants.BaseUri, "zones");

/// <summary>
/// Gets the <see cref="CloudFlareResponse{T}.Result"/> of a CloudFlare API <paramref name="response"/>.
/// Gets the <see cref="CloudFlareResponse{T}"/> of a CloudFlare API <paramref name="response"/>.
/// </summary>
/// <typeparam name="T">The type of the <see cref="CloudFlareResponse{T}.Result"/>.</typeparam>
public static async Task<CloudFlareResponse<T>> GetResultAsync<T>(
Expand All @@ -38,13 +38,13 @@ public static async Task<CloudFlareResponse<T>> GetResultAsync<T>(
.ConfigureAwait(false);
}

var errorResult = await response
.Content
.ReadAsAsync<CloudFlareResponseBase>(cancellationToken)
.ConfigureAwait(false);
CloudFlareResponseBase errorResponse =
await response
.Content
.ReadAsAsync<CloudFlareResponseBase>(cancellationToken)
.ConfigureAwait(false);

// TODO: Do some nice error handling.
throw new Exception("It's Not so good and stuff.");
throw new CloudFlareException(errorResponse, response);
}

/// <summary>
Expand Down
25 changes: 24 additions & 1 deletion src/Tests/CloudFlare.NET.Tests/DnsRecordClientSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,32 @@ public class When_getting_dnsRecords : RequestContext

It should_make_a_GET_request = () => _handler.Request.Method.ShouldEqual(HttpMethod.Get);

It should_request_the_zones_endpoint = () => _handler.Request.RequestUri.ShouldEqual(_expectedRequestUri);
It should_request_the_DNS_records_endpoint = () => _handler.Request.RequestUri.ShouldEqual(_expectedRequestUri);

It should_return_the_expected_zones = () =>
_actual.Select(z => z.AsLikeness().CreateProxy()).SequenceEqual(_expected).ShouldBeTrue();
}

[Subject(typeof(CloudFlareClient))]
public class When_getting_dnsRecords_and_an_error_occurs : ErredRequestContext
{
static IdentifierTag _zoneId;
static Uri _expectedRequestUri;

Establish context = () =>
{
_zoneId = _fixture.Create<IdentifierTag>();
_expectedRequestUri = new Uri(CloudFlareConstants.BaseUri, $"zones/{_zoneId}/dns_records");
};

Because of = () => _exception = Catch.Exception(() => _sut.GetDnsRecordsAsync(_zoneId, _auth).Await());

Behaves_like<AuthenticatedRequestBehaviour> authenticated_request_behaviour;

Behaves_like<ErredRequestBehaviour> erred_request_behaviour;

It should_make_a_GET_request = () => _handler.Request.Method.ShouldEqual(HttpMethod.Get);

It should_request_the_DNS_records_endpoint = () => _handler.Request.RequestUri.ShouldEqual(_expectedRequestUri);
}
}
13 changes: 13 additions & 0 deletions src/Tests/CloudFlare.NET.Tests/FixtureContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace CloudFlare.NET
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using CloudFlare.NET.HttpHandlers;
using Machine.Specifications;
Expand Down Expand Up @@ -31,4 +32,16 @@ public abstract class RequestContext : FixtureContext
_auth = _fixture.Create<CloudFlareAuth>();
};
}

public abstract class ErredRequestContext : RequestContext
{
protected static CloudFlareResponseBase _erredResponse;
protected static Exception _exception;

Establish context = () =>
{
_erredResponse = _fixture.Create<CloudFlareResponseBase>();
_handler.SetResponseContent(_erredResponse, (HttpStatusCode)new Random().Next(400, 600));
};
}
}
12 changes: 6 additions & 6 deletions src/Tests/CloudFlare.NET.Tests/HttpHandlers/TestHttpHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,19 @@ public HttpResponseMessage Response

public Func<HttpRequestMessage, Task<HttpRequestMessage>> OnSendingRequest { get; set; }

public void SetResponseContent(object content)
public void SetResponseContent(object content, HttpStatusCode code = HttpStatusCode.OK)
{
SetResponseContent(JObject.FromObject(content).ToString(Formatting.None));
SetResponseContent(JObject.FromObject(content).ToString(Formatting.None), code);
}

public void SetResponseContent(string content)
public void SetResponseContent(string content, HttpStatusCode code = HttpStatusCode.OK)
{
Response = CreateResponse(content);
Response = CreateResponse(content, code);
}

public void AddResponseContent(string content)
public void AddResponseContent(string content, HttpStatusCode code = HttpStatusCode.OK)
{
Responses.Add(CreateResponse(content));
Responses.Add(CreateResponse(content, code));
}

protected async override Task<HttpResponseMessage> SendAsync(
Expand Down
16 changes: 16 additions & 0 deletions src/Tests/CloudFlare.NET.Tests/LikenessExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,22 @@ public static Likeness<T, T> AsLikeness<T>(this T actual)
return actual.AsSource().OfLikeness<T>();
}

public static Likeness<CloudFlareResponseBase, CloudFlareResponseBase> AsLikeness(this CloudFlareResponseBase actual)
{
if (actual == null)
throw new ArgumentNullException(nameof(actual));

return actual
.AsSource()
.OfLikeness<CloudFlareResponseBase>()
.With(r => r.Errors)
.EqualsWhen((a, e) => a.Errors.SequenceEqual(e.Errors))
.With(r => r.Messages)
.EqualsWhen((a, e) => a.Messages.SequenceEqual(e.Messages))
.With(r => r.ResultInfo)
.EqualsWhen((a, e) => a.ResultInfo.AsLikeness().Equals(e.ResultInfo));
}

public static Likeness<Zone, Zone> AsLikeness(this Zone actual)
{
if (actual == null)
Expand Down
18 changes: 15 additions & 3 deletions src/Tests/CloudFlare.NET.Tests/RequestBehaviorTemplates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using CloudFlare.NET.HttpHandlers;
using Machine.Specifications;

Expand All @@ -14,10 +13,23 @@ public class AuthenticatedRequestBehaviour
protected static TestHttpHandler _handler;
protected static CloudFlareAuth _auth;

It It_should_provide_the_email_authentication_header = () =>
It should_provide_the_email_authentication_header = () =>
_handler.Request.Headers.GetValues("X-Auth-Email").Single().ShouldEqual(_auth.Email);

It It_should_provide_the_key_authentication_header = () =>
It should_provide_the_key_authentication_header = () =>
_handler.Request.Headers.GetValues("X-Auth-Key").Single().ShouldEqual(_auth.Key);
}

/// <seealso href="https://api.cloudflare.com/#responses"/>
[Behaviors]
public class ErredRequestBehaviour
{
protected static CloudFlareResponseBase _erredResponse;
protected static Exception _exception;

It should_throw_a_CloudFlareException = () => _exception.ShouldBeOfExactType<CloudFlareException>();

It should_contain_the_erred_response_in_the_exception =
() => ((CloudFlareException)_exception).Response.AsLikeness().ShouldEqual(_erredResponse);
}
}
45 changes: 45 additions & 0 deletions src/Tests/CloudFlare.NET.Tests/ZoneClientSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using Machine.Specifications;
using Ploeh.AutoFixture;
Expand Down Expand Up @@ -34,6 +35,27 @@ public class When_getting_all_zones : RequestContext
_actual.Select(z => z.AsLikeness().CreateProxy()).SequenceEqual(_expected).ShouldBeTrue();
}

[Subject(typeof(CloudFlareClient))]
public class When_getting_all_zones_and_an_error_occurs : ErredRequestContext
{
static Uri _expectedRequestUri;

Establish context = () =>
{
_expectedRequestUri = new Uri(CloudFlareConstants.BaseUri, "zones");
};

Because of = () => _exception = Catch.Exception(() => _sut.GetZonesAsync(_auth).Await());

Behaves_like<AuthenticatedRequestBehaviour> authenticated_request_behaviour;

Behaves_like<ErredRequestBehaviour> erred_request_behaviour;

It should_make_a_GET_request = () => _handler.Request.Method.ShouldEqual(HttpMethod.Get);

It should_request_the_zones_endpoint = () => _handler.Request.RequestUri.ShouldEqual(_expectedRequestUri);
}

[Subject(typeof(CloudFlareClient))]
public class When_getting_a_zone : RequestContext
{
Expand All @@ -59,4 +81,27 @@ public class When_getting_a_zone : RequestContext

It should_return_the_expected_zones = () => _actual.AsLikeness().ShouldEqual(_expected);
}

[Subject(typeof(CloudFlareClient))]
public class When_getting_a_zone_and_an_error_occurs : ErredRequestContext
{
static IdentifierTag _zoneId;
static Uri _expectedRequestUri;

Establish context = () =>
{
_zoneId = _fixture.Create<IdentifierTag>();
_expectedRequestUri = new Uri(CloudFlareConstants.BaseUri, $"zones/{_zoneId}");
};

Because of = () => _exception = Catch.Exception(() => _sut.GetZoneAsync(_zoneId, _auth).Await());

Behaves_like<AuthenticatedRequestBehaviour> authenticated_request_behaviour;

Behaves_like<ErredRequestBehaviour> erred_request_behaviour;

It should_make_a_GET_request = () => _handler.Request.Method.ShouldEqual(HttpMethod.Get);

It should_request_the_zone_endpoint = () => _handler.Request.RequestUri.ShouldEqual(_expectedRequestUri);
}
}

0 comments on commit c29a99a

Please sign in to comment.