From 0da8869950b94176ac582fbe741f5ec1db6f9a69 Mon Sep 17 00:00:00 2001 From: James Skimming Date: Fri, 31 Jul 2015 23:41:04 +0100 Subject: [PATCH 1/2] Added the Get Zones CloudFlare client method https://api.cloudflare.com/#zone-list-zones --- coverage.cmd | 8 +- src/Analyzers.ruleset | 2 + src/CloudFlare.NET/CloudFlare.NET.csproj | 14 ++- src/CloudFlare.NET/CloudFlareAuth.cs | 37 ++++++ src/CloudFlare.NET/CloudFlareClient.cs | 39 ++++++ src/CloudFlare.NET/CloudFlareConstants.cs | 18 +++ src/CloudFlare.NET/CloudFlareError.cs | 112 +++++++++++++++++ src/CloudFlare.NET/CloudFlareResponse.cs | 36 ++++++ src/CloudFlare.NET/CloudFlareResponseBase.cs | 61 ++++++++++ src/CloudFlare.NET/CloudFlareResultInfo.cs | 49 ++++++++ .../HttpClientZoneExtensions.cs | 62 ++++++++++ src/CloudFlare.NET/ICloudFlareClient.cs | 14 +++ src/CloudFlare.NET/IZoneClient.cs | 21 ++++ src/CloudFlare.NET/IdentifierTag.cs | 6 +- src/CloudFlare.NET/Zone.cs | 107 ++++++++++++++++ src/CloudFlare.NET/ZoneClientExtensions.cs | 26 ++++ .../CloudFlare.NET.Tests.csproj | 31 ++++- .../CloudFlare.NET.Tests.csproj.DotSettings | 1 + .../CloudFlareAuthSpec.cs | 33 +++++ .../CloudFlareErrorSpec.cs | 108 ++++++++++++++++ .../CloudFlare.NET.Tests/EqualsBehaviors.cs | 115 ++++++++++++++++++ .../CloudFlare.NET.Tests/FixtureContext.cs | 18 +++ .../CloudFlare.NET.Tests/IdentifierTagSpec.cs | 94 +++++++------- .../LikenessExtensions.cs | 20 +++ .../Serialization/ErrorResponse.json | 14 +++ .../ErrorResponseSerializationSpec.cs | 32 +++++ .../Serialization/SampleJson.cs | 34 ++++++ .../Serialization/SuccessResponse.json | 26 ++++ .../SuccessResponseSerializationSpec.cs | 51 ++++++++ .../Serialization/Zone.json | 69 +++++++++++ .../Serialization/ZoneSerializationSpec.cs | 47 +++++++ .../ZoneClientExtensionsSpec.cs | 37 ++++++ src/Tests/CloudFlare.NET.Tests/app.config | 2 +- .../CloudFlare.NET.Tests/packages.config | 2 + 34 files changed, 1286 insertions(+), 60 deletions(-) create mode 100644 src/CloudFlare.NET/CloudFlareAuth.cs create mode 100644 src/CloudFlare.NET/CloudFlareClient.cs create mode 100644 src/CloudFlare.NET/CloudFlareConstants.cs create mode 100644 src/CloudFlare.NET/CloudFlareError.cs create mode 100644 src/CloudFlare.NET/CloudFlareResponse.cs create mode 100644 src/CloudFlare.NET/CloudFlareResponseBase.cs create mode 100644 src/CloudFlare.NET/CloudFlareResultInfo.cs create mode 100644 src/CloudFlare.NET/HttpClientZoneExtensions.cs create mode 100644 src/CloudFlare.NET/ICloudFlareClient.cs create mode 100644 src/CloudFlare.NET/IZoneClient.cs create mode 100644 src/CloudFlare.NET/Zone.cs create mode 100644 src/CloudFlare.NET/ZoneClientExtensions.cs create mode 100644 src/Tests/CloudFlare.NET.Tests/CloudFlareAuthSpec.cs create mode 100644 src/Tests/CloudFlare.NET.Tests/CloudFlareErrorSpec.cs create mode 100644 src/Tests/CloudFlare.NET.Tests/EqualsBehaviors.cs create mode 100644 src/Tests/CloudFlare.NET.Tests/FixtureContext.cs create mode 100644 src/Tests/CloudFlare.NET.Tests/LikenessExtensions.cs create mode 100644 src/Tests/CloudFlare.NET.Tests/Serialization/ErrorResponse.json create mode 100644 src/Tests/CloudFlare.NET.Tests/Serialization/ErrorResponseSerializationSpec.cs create mode 100644 src/Tests/CloudFlare.NET.Tests/Serialization/SampleJson.cs create mode 100644 src/Tests/CloudFlare.NET.Tests/Serialization/SuccessResponse.json create mode 100644 src/Tests/CloudFlare.NET.Tests/Serialization/SuccessResponseSerializationSpec.cs create mode 100644 src/Tests/CloudFlare.NET.Tests/Serialization/Zone.json create mode 100644 src/Tests/CloudFlare.NET.Tests/Serialization/ZoneSerializationSpec.cs create mode 100644 src/Tests/CloudFlare.NET.Tests/ZoneClientExtensionsSpec.cs diff --git a/coverage.cmd b/coverage.cmd index 1911795..2526d7e 100644 --- a/coverage.cmd +++ b/coverage.cmd @@ -39,13 +39,13 @@ @SET coverage_results=%~dp0src\TestResults\Test.Coverage.xml @IF NOT EXIST "%~dp0src\TestResults" MD "%~dp0src\TestResults" -::@echo "%mspec_exe%" "%test_assemblies%" --html "%spec_results%" -::@"%mspec_exe%" "%test_assemblies%" --html "%spec_results%" +::@echo "%mspec_exe%" "%test_assemblies%" --timeinfo --silent --html "%spec_results%" +::@"%mspec_exe%" "%test_assemblies%" --timeinfo --silent --html "%spec_results%" ::@echo "%xunit_exe%" "%test_assemblies%" -noshadow -html "%xunit_results%" ::@"%xunit_exe%" "%test_assemblies%" -noshadow -html "%xunit_results%" -@echo "%cover_exe%" -register:user "-target:%mspec_exe%" "-targetargs:%test_assemblies% --html %spec_results%" -filter:%coverage_filter% "-output:%coverage_results%" -@"%cover_exe%" -register:user "-target:%mspec_exe%" "-targetargs:%test_assemblies% --html %spec_results%" -filter:%coverage_filter% "-output:%coverage_results%" +@echo "%cover_exe%" -register:user "-target:%mspec_exe%" "-targetargs:%test_assemblies% --timeinfo --silent --html %spec_results%" -filter:%coverage_filter% "-output:%coverage_results%" +@"%cover_exe%" -register:user "-target:%mspec_exe%" "-targetargs:%test_assemblies% --timeinfo --silent --html %spec_results%" -filter:%coverage_filter% "-output:%coverage_results%" @echo "%cover_exe%" -register:user "-target:%xunit_exe%" "-targetargs:%test_assemblies% -noshadow -html %xunit_results%" -mergeoutput -filter:%coverage_filter% "-output:%coverage_results%" @"%cover_exe%" -register:user "-target:%xunit_exe%" "-targetargs:%test_assemblies% -noshadow -html %xunit_results%" -mergeoutput -filter:%coverage_filter% "-output:%coverage_results%" diff --git a/src/Analyzers.ruleset b/src/Analyzers.ruleset index fc35ee8..77cea96 100644 --- a/src/Analyzers.ruleset +++ b/src/Analyzers.ruleset @@ -7,6 +7,8 @@ + + \ No newline at end of file diff --git a/src/CloudFlare.NET/CloudFlare.NET.csproj b/src/CloudFlare.NET/CloudFlare.NET.csproj index f069869..6015938 100644 --- a/src/CloudFlare.NET/CloudFlare.NET.csproj +++ b/src/CloudFlare.NET/CloudFlare.NET.csproj @@ -63,12 +63,24 @@ + + + + + + + + + - + + + + diff --git a/src/CloudFlare.NET/CloudFlareAuth.cs b/src/CloudFlare.NET/CloudFlareAuth.cs new file mode 100644 index 0000000..f742deb --- /dev/null +++ b/src/CloudFlare.NET/CloudFlareAuth.cs @@ -0,0 +1,37 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + + /// + /// Represents the authorization parameters for accessing the CloudFlare API. + /// + /// + public class CloudFlareAuth + { + /// + /// Initializes a new instance of the class. + /// + public CloudFlareAuth(string email, string key) + { + if (string.IsNullOrWhiteSpace(email)) + throw new ArgumentNullException(nameof(email)); + if (string.IsNullOrWhiteSpace(key)) + throw new ArgumentNullException(nameof(key)); + + Email = email; + Key = key; + } + + /// + /// Gets the Email address associated with your account. + /// + public string Email { get; } + + /// + /// Gets the API key generated on the "My Account" page. + /// + public string Key { get; } + } +} diff --git a/src/CloudFlare.NET/CloudFlareClient.cs b/src/CloudFlare.NET/CloudFlareClient.cs new file mode 100644 index 0000000..80a059a --- /dev/null +++ b/src/CloudFlare.NET/CloudFlareClient.cs @@ -0,0 +1,39 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Net.Http; + using System.Net.Http.Headers; + using System.Threading; + using System.Threading.Tasks; + + /// + public class CloudFlareClient : ICloudFlareClient + { + private static readonly Lazy LazyClient = new Lazy( + () => + { + var client = new HttpClient( + new HttpClientHandler + { + AutomaticDecompression = DecompressionMethods.GZip, + }) + ; + + client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + + return client; + }, + LazyThreadSafetyMode.PublicationOnly); + + private static HttpClient Client => LazyClient.Value; + + /// + public Task> GetZonesAsync(CancellationToken cancellationToken, CloudFlareAuth auth = null) + { + return Client.GetZonesAsync(auth, cancellationToken); + } + } +} diff --git a/src/CloudFlare.NET/CloudFlareConstants.cs b/src/CloudFlare.NET/CloudFlareConstants.cs new file mode 100644 index 0000000..4b6cd4b --- /dev/null +++ b/src/CloudFlare.NET/CloudFlareConstants.cs @@ -0,0 +1,18 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + + /// + /// Constants for CloudFlare. + /// + public static class CloudFlareConstants + { + /// + /// Gets the base address of the CloudFlare API. + /// + /// + public static Uri BaseUri { get; } = new Uri("https://api.cloudflare.com/client/v4/", UriKind.Absolute); + } +} diff --git a/src/CloudFlare.NET/CloudFlareError.cs b/src/CloudFlare.NET/CloudFlareError.cs new file mode 100644 index 0000000..270a047 --- /dev/null +++ b/src/CloudFlare.NET/CloudFlareError.cs @@ -0,0 +1,112 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + + /// + /// Represents an error that can occur as a result of a CloudFlare API request. + /// + /// + public class CloudFlareError : IEquatable + { + /// + /// Initializes a new instance of the class. + /// + public CloudFlareError(int code, string message = null) + { + Code = code; + Message = message ?? string.Empty; + } + + /// + /// Gets the error code. + /// + [JsonProperty("code")] + public int Code { get; } + + /// + /// Gets the error message. + /// + [JsonProperty("message")] + public string Message { get; } + + /// + /// The implicit operator to return the of a . + /// + public static implicit operator int(CloudFlareError error) + { + if (error == null) + throw new ArgumentNullException(nameof(error)); + + return error.Code; + } + + /// + /// Determines whether two specified objects have the same value. + /// + /// The first to compare, or . + /// The second to compare, or . + /// + /// if the value of is the same as the value of + /// ; otherwise, . + public static bool operator ==(CloudFlareError left, CloudFlareError right) => Equals(left, right); + + /// + /// Determines whether two specified objects have different values. + /// + /// The first to compare, or . + /// The second to compare, or . + /// + /// if the value of is different from the value of + /// ; otherwise, . + /// + public static bool operator !=(CloudFlareError left, CloudFlareError right) => !Equals(left, right); + + /// + /// Indicates whether the current is equal to another object + /// . + /// + /// An object to compare with this object. + /// + /// if the current object is equal to the parameter; + /// otherwise, + /// . + /// + public bool Equals(CloudFlareError other) + { + if (ReferenceEquals(null, other)) + return false; + if (ReferenceEquals(this, other)) + return true; + + return Code == other.Code; + } + + /// + /// Determines whether the specified object is equal to the current object. + /// + /// The object to compare with the current object. + /// + /// if the specified object is equal to the current object; otherwise, + /// . + /// + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj.GetType() != GetType()) + return false; + + return Equals((CloudFlareError)obj); + } + + /// + /// Gets a hash code for the current object. + /// + public override int GetHashCode() => Code; + } +} diff --git a/src/CloudFlare.NET/CloudFlareResponse.cs b/src/CloudFlare.NET/CloudFlareResponse.cs new file mode 100644 index 0000000..4eefd1f --- /dev/null +++ b/src/CloudFlare.NET/CloudFlareResponse.cs @@ -0,0 +1,36 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + + /// + /// Represent the base generic response from CloudFlare indicating success or failure. + /// + /// The type of the . + /// + public class CloudFlareResponse : CloudFlareResponseBase + where T : class + { + /// + /// Initializes a new instance of the class. + /// + public CloudFlareResponse( + bool success, + T result = null, + IReadOnlyList errors = null, + IReadOnlyList messages = null, + CloudFlareResultInfo resultInfo = null) + : base(success, errors, messages, resultInfo) + { + Result = result; + } + + /// + /// Gets the result of the request. + /// + [JsonProperty("result")] + public T Result { get; } + } +} diff --git a/src/CloudFlare.NET/CloudFlareResponseBase.cs b/src/CloudFlare.NET/CloudFlareResponseBase.cs new file mode 100644 index 0000000..a72e421 --- /dev/null +++ b/src/CloudFlare.NET/CloudFlareResponseBase.cs @@ -0,0 +1,61 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + + /// + /// Represent the base response from CloudFlare indicating success or failure. + /// + /// + public class CloudFlareResponseBase + { + private static readonly IReadOnlyList EmptyErrors = + Enumerable.Empty().ToList(); + + private static readonly CloudFlareResultInfo DefaultResultInfo = + new CloudFlareResultInfo(-1, -1, -1, -1); + + private static readonly IReadOnlyList EmptyMessages = Enumerable.Empty().ToList(); + + /// + /// Initializes a new instance of the class. + /// + public CloudFlareResponseBase( + bool success, + IReadOnlyList errors = null, + IReadOnlyList messages = null, + CloudFlareResultInfo resultInfo = null) + { + Success = success; + Errors = errors ?? EmptyErrors; + Messages = messages ?? EmptyMessages; + ResultInfo = resultInfo ?? DefaultResultInfo; + } + + /// + /// Gets the value indicating whether the request was successful. + /// + [JsonProperty("success")] + public bool Success { get; } + + /// + /// Gets the errors for unsuccessful requests. + /// + [JsonProperty("errors")] + public IReadOnlyList Errors { get; } + + /// + /// Gets the messages for unsuccessful requests. + /// + [JsonProperty("messages")] + public IReadOnlyList Messages { get; } + + /// + /// Gets the result info about the request. + /// + [JsonProperty("result_info")] + public CloudFlareResultInfo ResultInfo { get; } + } +} diff --git a/src/CloudFlare.NET/CloudFlareResultInfo.cs b/src/CloudFlare.NET/CloudFlareResultInfo.cs new file mode 100644 index 0000000..c8ac0d2 --- /dev/null +++ b/src/CloudFlare.NET/CloudFlareResultInfo.cs @@ -0,0 +1,49 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + + /// + /// Represent additional pagination information from successful CloudFlare API requests. + /// + /// + public class CloudFlareResultInfo + { + /// + /// Initializes a new instance of the class. + /// + public CloudFlareResultInfo(int page, int perPage, int count, int totalCount) + { + Page = page; + PerPage = perPage; + Count = count; + TotalCount = totalCount; + } + + /// + /// Gets the TBD. + /// + [JsonProperty("page")] + public int Page { get; } + + /// + /// Gets the TBD. + /// + [JsonProperty("per_page")] + public int PerPage { get; } + + /// + /// Gets the TBD. + /// + [JsonProperty("count")] + public int Count { get; } + + /// + /// Gets the TBD. + /// + [JsonProperty("total_count")] + public int TotalCount { get; } + } +} diff --git a/src/CloudFlare.NET/HttpClientZoneExtensions.cs b/src/CloudFlare.NET/HttpClientZoneExtensions.cs new file mode 100644 index 0000000..9939450 --- /dev/null +++ b/src/CloudFlare.NET/HttpClientZoneExtensions.cs @@ -0,0 +1,62 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods on to wrap the Zone APIs + /// + /// + public static class HttpClientZoneExtensions + { + /// + /// Gets the base address of the CloudFlare API. + /// + public static Uri ZonesUri { get; } = new Uri(CloudFlareConstants.BaseUri, "zones"); + + /// + /// Gets the zones for the account specified by the details. + /// + /// The zones for the subscription. + public static async Task> GetZonesAsync( + this HttpClient client, + CloudFlareAuth auth, + CancellationToken cancellationToken) + { + if (client == null) + throw new ArgumentNullException(nameof(client)); + if (auth == null) + throw new ArgumentNullException(nameof(auth)); + + var request = new HttpRequestMessage(HttpMethod.Get, ZonesUri); + request.Headers.Add("X-Auth-Key", auth.Key); + request.Headers.Add("X-Auth-Email", auth.Email); + + HttpResponseMessage response = + await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken) + .ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + var result = await response + .Content + .ReadAsAsync>>(cancellationToken) + .ConfigureAwait(false); + + return result.Result; + } + + var errorResult = await response + .Content + .ReadAsAsync(cancellationToken) + .ConfigureAwait(false); + + // TODO: Do some nice error handling. + throw new Exception("It's Not so good and stuff."); + } + } +} diff --git a/src/CloudFlare.NET/ICloudFlareClient.cs b/src/CloudFlare.NET/ICloudFlareClient.cs new file mode 100644 index 0000000..d648740 --- /dev/null +++ b/src/CloudFlare.NET/ICloudFlareClient.cs @@ -0,0 +1,14 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + + /// + /// The CloudFlare API Client. + /// + /// + public interface ICloudFlareClient : IZoneClient + { + } +} diff --git a/src/CloudFlare.NET/IZoneClient.cs b/src/CloudFlare.NET/IZoneClient.cs new file mode 100644 index 0000000..a81c53c --- /dev/null +++ b/src/CloudFlare.NET/IZoneClient.cs @@ -0,0 +1,21 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + + /// + /// The CloudFlare API Client. + /// + /// + public interface IZoneClient + { + /// + /// Gets the zones for the subscription. + /// + /// The zones for the subscription. + Task> GetZonesAsync(CancellationToken cancellationToken, CloudFlareAuth auth = null); + } +} diff --git a/src/CloudFlare.NET/IdentifierTag.cs b/src/CloudFlare.NET/IdentifierTag.cs index 27b8558..4f5f613 100644 --- a/src/CloudFlare.NET/IdentifierTag.cs +++ b/src/CloudFlare.NET/IdentifierTag.cs @@ -21,7 +21,7 @@ public partial class IdentifierTag /// /// Initializes a new instance of the class. /// - /// The unique identifier of an entity in CloudFlair. + /// The unique identifier of an entity in CloudFlare. public IdentifierTag(string id) { if (id == null) @@ -47,13 +47,13 @@ public IdentifierTag(string id) /// /// The implicit operator to create a new from a string. /// - /// The unique identifier of an entity in CloudFlair. + /// The unique identifier of an entity in CloudFlare. public static implicit operator IdentifierTag(string id) => new IdentifierTag(id); /// /// The implicit operator to return the string representation of an . /// - /// The unique identifier of an entity in CloudFlair. + /// The unique identifier of an entity in CloudFlare. public static implicit operator string(IdentifierTag identifier) { if (identifier == null) diff --git a/src/CloudFlare.NET/Zone.cs b/src/CloudFlare.NET/Zone.cs new file mode 100644 index 0000000..0329b1a --- /dev/null +++ b/src/CloudFlare.NET/Zone.cs @@ -0,0 +1,107 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + + /// + /// A Zone is a domain name along with its subdomains and other identities. + /// + /// + public class Zone + { + private static readonly IReadOnlyList EmptyString = Enumerable.Empty().ToList(); + + /// + /// Initializes a new instance of the class. + /// + public Zone( + IdentifierTag id, + string name, + int developmentMode, + IReadOnlyList originalNameServers, + string originalRegistrar, + string originalDnshost, + DateTimeOffset createdOn, + DateTimeOffset modifiedOn, + IReadOnlyList nameServers = null) + { + if (id == null) + throw new ArgumentNullException(nameof(id)); + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentNullException(nameof(name)); + if (originalNameServers == null) + throw new ArgumentNullException(nameof(originalNameServers)); + if (string.IsNullOrWhiteSpace(originalRegistrar)) + throw new ArgumentNullException(nameof(originalRegistrar)); + if (string.IsNullOrWhiteSpace(originalDnshost)) + throw new ArgumentNullException(nameof(originalDnshost)); + + Id = id; + Name = name; + DevelopmentMode = developmentMode; + OriginalNameServers = originalNameServers; + OriginalRegistrar = originalRegistrar; + OriginalDnshost = originalDnshost; + CreatedOn = createdOn; + ModifiedOn = modifiedOn; + NameServers = nameServers ?? EmptyString; + } + + /// + /// API item identifier tag. + /// + [JsonProperty("id")] + public IdentifierTag Id { get; } + + /// + /// The domain name. + /// + [JsonProperty("name")] + public string Name { get; } + + /// + /// The interval (in seconds) from when development mode expires (positive integer) or last expired (negative + /// integer) for the domain. If development mode has never been enabled, this value is 0. + /// + [JsonProperty("development_mode")] + public int DevelopmentMode { get; } + + /// + /// Original name servers before moving to CloudFlare. + /// + [JsonProperty("original_name_servers")] + public IReadOnlyList OriginalNameServers { get; } + + /// + /// Registrar for the domain at the time of switching to CloudFlare. + /// + [JsonProperty("original_registrar")] + public string OriginalRegistrar { get; } + + /// + /// DNS host at the time of switching to CloudFlare. + /// + [JsonProperty("original_dnshost")] + public string OriginalDnshost { get; } + + /// + /// When the zone was created. + /// + [JsonProperty("created_on")] + public DateTimeOffset CreatedOn { get; } + + /// + /// When the zone was last modified. + /// + [JsonProperty("modified_on")] + public DateTimeOffset ModifiedOn { get; } + + /// + /// CloudFlare-assigned name servers. This is only populated for zones that use CloudFlare DNS. + /// + [JsonProperty("name_servers")] + public IReadOnlyList NameServers { get; } + } +} diff --git a/src/CloudFlare.NET/ZoneClientExtensions.cs b/src/CloudFlare.NET/ZoneClientExtensions.cs new file mode 100644 index 0000000..8b55b48 --- /dev/null +++ b/src/CloudFlare.NET/ZoneClientExtensions.cs @@ -0,0 +1,26 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Helper extension methods on . + /// + public static class ZoneClientExtensions + { + /// + /// Gets the zones for the subscription. + /// + /// The zones for the subscription. + public static Task> GetZonesAsync(this IZoneClient client, CloudFlareAuth auth = null) + { + if (client == null) + throw new ArgumentNullException(nameof(client)); + + return client.GetZonesAsync(CancellationToken.None, auth); + } + } +} diff --git a/src/Tests/CloudFlare.NET.Tests/CloudFlare.NET.Tests.csproj b/src/Tests/CloudFlare.NET.Tests/CloudFlare.NET.Tests.csproj index d33f2c2..0942aa6 100644 --- a/src/Tests/CloudFlare.NET.Tests/CloudFlare.NET.Tests.csproj +++ b/src/Tests/CloudFlare.NET.Tests/CloudFlare.NET.Tests.csproj @@ -20,6 +20,7 @@ DEBUG;TRACE prompt 4 + 169 pdbonly @@ -28,6 +29,7 @@ TRACE prompt 4 + 169 @@ -55,6 +57,10 @@ ..\..\packages\Moq.4.2.1507.0118\lib\net40\Moq.dll True + + ..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + True + ..\..\packages\AutoFixture.3.31.0\lib\net40\Ploeh.AutoFixture.dll True @@ -67,6 +73,10 @@ ..\..\packages\AutoFixture.Xunit.3.31.0\lib\net40\Ploeh.AutoFixture.Xunit.dll True + + ..\..\packages\SemanticComparison.3.31.0\lib\net40\Ploeh.SemanticComparison.dll + True + @@ -89,11 +99,26 @@ + + + + - + + + + + + + + + + + + @@ -101,10 +126,6 @@ CloudFlare.NET - - - - diff --git a/src/Tests/CloudFlare.NET.Tests/CloudFlare.NET.Tests.csproj.DotSettings b/src/Tests/CloudFlare.NET.Tests/CloudFlare.NET.Tests.csproj.DotSettings index c5a7168..0063a2a 100644 --- a/src/Tests/CloudFlare.NET.Tests/CloudFlare.NET.Tests.csproj.DotSettings +++ b/src/Tests/CloudFlare.NET.Tests/CloudFlare.NET.Tests.csproj.DotSettings @@ -1,4 +1,5 @@  + DO_NOT_SHOW DO_NOT_SHOW DO_NOT_SHOW False diff --git a/src/Tests/CloudFlare.NET.Tests/CloudFlareAuthSpec.cs b/src/Tests/CloudFlare.NET.Tests/CloudFlareAuthSpec.cs new file mode 100644 index 0000000..9e8d078 --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/CloudFlareAuthSpec.cs @@ -0,0 +1,33 @@ +namespace CloudFlare.NET.AuthSpecs +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Machine.Specifications; + using Newtonsoft.Json.Linq; + using Ploeh.AutoFixture; + + [Subject(typeof(CloudFlareAuth))] + public class When_initializing + { + static string _email; + static string _key; + static CloudFlareAuth _auth; + static CloudFlareAuth _authCopy; + + Because of = () => + { + var fixture = new Fixture(); + _email = fixture.Create(); + _key = fixture.Create(); + _auth = new CloudFlareAuth(_email, _key); + _authCopy = JObject.FromObject(_auth).ToObject(); + }; + + It should_initialize_code = () => _auth.Email.ShouldBeTheSameAs(_email); + + It should_initialize_key = () => _auth.Key.ShouldBeTheSameAs(_key); + + It should_serialze_as_json = () => _authCopy.AsLikeness().ShouldEqual(_auth); + } +} diff --git a/src/Tests/CloudFlare.NET.Tests/CloudFlareErrorSpec.cs b/src/Tests/CloudFlare.NET.Tests/CloudFlareErrorSpec.cs new file mode 100644 index 0000000..0f8337d --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/CloudFlareErrorSpec.cs @@ -0,0 +1,108 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Machine.Specifications; + using Ploeh.AutoFixture; + + [Subject(typeof(CloudFlareError))] + public class When_evaluating_error_equality_via_default_Equals + { + protected static object _source; + protected static object _same; + protected static object _different; + + Because of = () => + { + _source = new CloudFlareError(1); + _same = new CloudFlareError(1); + _different = new CloudFlareError(2); + }; + + Behaves_like default_equals_behavior; + } + + [Subject(typeof(CloudFlareError))] + public class When_evaluating_error_equality_via_typed_Equals + { + protected static CloudFlareError _source; + protected static CloudFlareError _same; + protected static CloudFlareError _different; + + Because of = () => + { + _source = new CloudFlareError(1); + _same = new CloudFlareError(1); + _different = new CloudFlareError(2); + }; + + Behaves_like> typed_equals_behavior; + } + + [Subject(typeof(CloudFlareError))] + public class When_evaluating_error_equality_via_Equals_operator + { + protected static Func _equals; + protected static CloudFlareError _source; + protected static CloudFlareError _same; + protected static CloudFlareError _different; + protected static CloudFlareError _differentType; + + Because of = () => + { + _equals = (l, r) => l == r; + _source = new CloudFlareError(1); + _same = new CloudFlareError(1); + _different = new CloudFlareError(2); + _differentType = new Moq.Mock(1, string.Empty).Object; + }; + + Behaves_like> equals_operator_behavior; + } + + [Subject(typeof(CloudFlareError))] + public class When_evaluating_error_enequality_via_Notequals_operator + { + protected static Func _notequals; + protected static CloudFlareError _source; + protected static CloudFlareError _same; + protected static CloudFlareError _different; + protected static CloudFlareError _differentType; + + Because of = () => + { + _notequals = (l, r) => l != r; + _source = new CloudFlareError(1); + _same = new CloudFlareError(1); + _different = new CloudFlareError(2); + _differentType = new Moq.Mock(1, string.Empty).Object; + }; + + Behaves_like> notequals_operator_behavior; + } + + [Subject(typeof(CloudFlareError))] + public class When_initializing_an_error + { + static int _code; + static string _message; + static CloudFlareError _error; + + Because of = () => + { + var fixture = new Fixture(); + _code = fixture.Freeze(); + _message = fixture.Freeze(); + _error = fixture.Freeze(); + }; + + It should_initialize_the_code = () => _error.Code.ShouldEqual(_code); + + It should_initialize_the_message = () => _error.Message.ShouldEqual(_message); + + It should_be_equal_to_the_same_code = () => (_code == _error).ShouldBeTrue(); + + It should_have_the_same_hashcode_as_the_code = () => _error.GetHashCode().ShouldEqual(_code); + } +} diff --git a/src/Tests/CloudFlare.NET.Tests/EqualsBehaviors.cs b/src/Tests/CloudFlare.NET.Tests/EqualsBehaviors.cs new file mode 100644 index 0000000..92ff535 --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/EqualsBehaviors.cs @@ -0,0 +1,115 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Machine.Specifications; + + [Behaviors] + public class DefaultEqualsBehavior + { + protected static object _source; + protected static object _same; + protected static object _different; + + It should_be_equal_when_compared_against_the_same_reference = + () => _source.Equals(_source).ShouldBeTrue(); + + It should_be_equal_when_compared_against_the_same_value = + () => _source.Equals(_same).ShouldBeTrue(); + + It should_not_be_equal_when_compared_against_the_a_different_value = + () => _source.Equals(_different).ShouldBeFalse(); + + It should_not_be_equal_when_compared_against_a_different_type = + () => _source.Equals(Guid.NewGuid()).ShouldBeFalse(); + + It should_not_be_equal_when_compared_against_null = + () => _source.Equals(null).ShouldBeFalse(); + } + + [Behaviors] + public class TypedEqualsBehavior + where T : class, IEquatable + { + protected static T _source; + protected static T _same; + protected static T _different; + + It should_be_equal_when_compared_against_the_same_reference = + () => _source.Equals(_source).ShouldBeTrue(); + + It should_be_equal_when_compared_against_the_same_value = + () => _source.Equals(_same).ShouldBeTrue(); + + It should_not_be_equal_when_compared_against_the_a_different_value = + () => _source.Equals(_different).ShouldBeFalse(); + + It should_not_be_equal_when_compared_against_null = + () => _source.Equals(default(T)).ShouldBeFalse(); + } + + [Behaviors] + public class ComparerEqualsBehavior + where T : class + { + protected static Func _equals; + protected static T _source; + protected static T _same; + protected static T _different; + protected static T _differentType; + + It should_be_equal_when_compared_against_the_same_reference = + () => _equals(_source, _source).ShouldBeTrue(); + + It should_be_equal_when_both_operands_null = + () => _equals(null, null).ShouldBeTrue(); + + It should_be_equal_when_compared_against_the_same_value = + () => _equals(_source, _same).ShouldBeTrue(); + + It should_not_be_equal_when_compared_against_the_a_different_value = + () => _equals(_source, _different).ShouldBeFalse(); + + It should_not_be_equal_when_compared_against_null_lhs = + () => _equals(null, _source).ShouldBeFalse(); + + It should_not_be_equal_when_compared_against_null_rhs = + () => _equals(_source, null).ShouldBeFalse(); + + It should_not_be_equal_when_compared_against_different_type = + () => _equals(_source, _differentType).ShouldBeFalse(); + } + + [Behaviors] + public class ComparerNotEqualsBehavior + where T : class + { + protected static Func _notequals; + protected static T _source; + protected static T _same; + protected static T _different; + protected static T _differentType; + + It should_be_inequal_when_compared_against_the_same_reference = + () => _notequals(_source, _source).ShouldBeFalse(); + + It should_be_inequal_when_both_operands_null = + () => _notequals(null, null).ShouldBeFalse(); + + It should_be_inequal_when_compared_against_the_same_value = + () => _notequals(_source, _same).ShouldBeFalse(); + + It should_not_be_inequal_when_compared_against_the_a_different_value = + () => _notequals(_source, _different).ShouldBeTrue(); + + It should_not_be_inequal_when_compared_against_null_lhs = + () => _notequals(null, _source).ShouldBeTrue(); + + It should_not_be_inequal_when_compared_against_null_rhs = + () => _notequals(_source, null).ShouldBeTrue(); + + It should_not_be_inequal_when_compared_against_different_type = + () => _notequals(_source, _differentType).ShouldBeTrue(); + } +} diff --git a/src/Tests/CloudFlare.NET.Tests/FixtureContext.cs b/src/Tests/CloudFlare.NET.Tests/FixtureContext.cs new file mode 100644 index 0000000..717e485 --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/FixtureContext.cs @@ -0,0 +1,18 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Machine.Specifications; + using Ploeh.AutoFixture; + + public abstract class FixtureContext + { + protected static IFixture _fixture; + + Establish context = () => + { + _fixture = new Fixture().Customize(new CloudFlareCustomization()); + }; + } +} diff --git a/src/Tests/CloudFlare.NET.Tests/IdentifierTagSpec.cs b/src/Tests/CloudFlare.NET.Tests/IdentifierTagSpec.cs index 0e783f9..3172e97 100644 --- a/src/Tests/CloudFlare.NET.Tests/IdentifierTagSpec.cs +++ b/src/Tests/CloudFlare.NET.Tests/IdentifierTagSpec.cs @@ -34,7 +34,7 @@ public class When_initializing_with_a_guid_string static IdentifierTag _constructorCreated; static IdentifierTag _implicitCreated; - Establish context = () => + Because of = () => { _guid = Guid.NewGuid().ToString("N"); _constructorCreated = new IdentifierTag(_guid); @@ -87,97 +87,99 @@ public class When_initializing_with_a_guid_string } [Subject(typeof(IdentifierTag))] - public class When_evaluating_equality_via_default_Equals + public class When_evaluating_identifier_equality_via_default_Equals { protected static object _source; protected static object _same; protected static object _different; - Establish context = () => + Because of = () => { _source = new IdentifierTag(Guid.NewGuid().ToString("N")); _same = new IdentifierTag(_source.ToString()); _different = new IdentifierTag(Guid.NewGuid().ToString("N")); }; - It should_be_equal_when_compared_against_the_same_reference = - () => _source.Equals(_source).ShouldBeTrue(); - - It should_be_equal_when_compared_against_the_same_value = - () => _source.Equals(_same).ShouldBeTrue(); - - It should_not_be_equal_when_compared_against_the_a_different_value = - () => _source.Equals(_different).ShouldBeFalse(); - - It should_not_be_equal_when_compared_against_a_different_type = - () => _source.Equals(Guid.NewGuid()).ShouldBeFalse(); - - It should_not_be_equal_when_compared_against_null = - () => _source.Equals(null).ShouldBeFalse(); + Behaves_like default_equals_behavior; } [Subject(typeof(IdentifierTag))] - public class When_evaluating_equality_via_typed_Equals + public class When_evaluating_identifier_equality_via_typed_Equals { protected static IdentifierTag _source; protected static IdentifierTag _same; protected static IdentifierTag _different; - Establish context = () => + Because of = () => { _source = new IdentifierTag(Guid.NewGuid().ToString("N")); _same = new IdentifierTag(_source.ToString()); _different = new IdentifierTag(Guid.NewGuid().ToString("N")); }; - It should_be_equal_when_compared_against_the_same_reference = - () => _source.Equals(_source).ShouldBeTrue(); - - It should_be_equal_when_compared_against_the_same_value = - () => _source.Equals(_same).ShouldBeTrue(); - - It should_not_be_equal_when_compared_against_the_a_different_value = - () => _source.Equals(_different).ShouldBeFalse(); - - It should_not_be_equal_when_compared_against_null = - () => _source.Equals(null).ShouldBeFalse(); + Behaves_like> typed_equals_behavior; } [Subject(typeof(IdentifierTag))] - public class When_evaluating_equality_via_Comparer_Equals + public class When_evaluating_identifier_equality_via_Comparer_Equals { + protected static Func _equals; protected static IdentifierTag _source; protected static IdentifierTag _same; protected static IdentifierTag _different; protected static IdentifierTag _differentType; - Establish context = () => + Because of = () => { + _equals = IdentifierTag.Comparer.Equals; _source = new IdentifierTag(Guid.NewGuid().ToString("N")); _same = new IdentifierTag(_source.ToString()); _different = new IdentifierTag(Guid.NewGuid().ToString("N")); _differentType = new Moq.Mock(_source.ToString()).Object; }; - It should_be_equal_when_compared_against_the_same_reference = - () => IdentifierTag.Comparer.Equals(_source, _source).ShouldBeTrue(); + Behaves_like> equals_operator_behavior; + } - It should_be_equal_when_both_operands_null = - () => IdentifierTag.Comparer.Equals(null, null).ShouldBeTrue(); + [Subject(typeof(IdentifierTag))] + public class When_evaluating_identifier_equality_via_Equals_operator + { + protected static Func _equals; + protected static IdentifierTag _source; + protected static IdentifierTag _same; + protected static IdentifierTag _different; + protected static IdentifierTag _differentType; - It should_be_equal_when_compared_against_the_same_value = - () => IdentifierTag.Comparer.Equals(_source, _same).ShouldBeTrue(); + Because of = () => + { + _equals = (l, r) => l == r; + _source = new IdentifierTag(Guid.NewGuid().ToString("N")); + _same = new IdentifierTag(_source.ToString()); + _different = new IdentifierTag(Guid.NewGuid().ToString("N")); + _differentType = new Moq.Mock(_source.ToString()).Object; + }; - It should_not_be_equal_when_compared_against_the_a_different_value = - () => IdentifierTag.Comparer.Equals(_source, _different).ShouldBeFalse(); + Behaves_like> equals_operator_behavior; + } - It should_not_be_equal_when_compared_against_null_lhs = - () => IdentifierTag.Comparer.Equals(null, _source).ShouldBeFalse(); + [Subject(typeof(IdentifierTag))] + public class When_evaluating_identifier_enequality_via_Notequals_operator + { + protected static Func _notequals; + protected static IdentifierTag _source; + protected static IdentifierTag _same; + protected static IdentifierTag _different; + protected static IdentifierTag _differentType; - It should_not_be_equal_when_compared_against_null_rhs = - () => IdentifierTag.Comparer.Equals(_source, null).ShouldBeFalse(); + Because of = () => + { + _notequals = (l, r) => l != r; + _source = new IdentifierTag(Guid.NewGuid().ToString("N")); + _same = new IdentifierTag(_source.ToString()); + _different = new IdentifierTag(Guid.NewGuid().ToString("N")); + _differentType = new Moq.Mock(_source.ToString()).Object; + }; - It should_not_be_equal_when_compared_against_different_type = - () => IdentifierTag.Comparer.Equals(_source, _differentType).ShouldBeFalse(); + Behaves_like> notequals_operator_behavior; } } diff --git a/src/Tests/CloudFlare.NET.Tests/LikenessExtensions.cs b/src/Tests/CloudFlare.NET.Tests/LikenessExtensions.cs new file mode 100644 index 0000000..0df8abc --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/LikenessExtensions.cs @@ -0,0 +1,20 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Ploeh.SemanticComparison; + using Ploeh.SemanticComparison.Fluent; + + internal static class LikenessExtensions + { + public static Likeness AsLikeness(this T actual) + where T : class + { + if (actual == null) + throw new ArgumentNullException(nameof(actual)); + + return actual.AsSource().OfLikeness(); + } + } +} diff --git a/src/Tests/CloudFlare.NET.Tests/Serialization/ErrorResponse.json b/src/Tests/CloudFlare.NET.Tests/Serialization/ErrorResponse.json new file mode 100644 index 0000000..3e88768 --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/Serialization/ErrorResponse.json @@ -0,0 +1,14 @@ +{ + "result": {}, + "success": false, + "errors": [ + { + "code": 1003, + "message": "Invalid or missing zone id." + } + ], + "messages": [ + "Message 1", + "Message 1" + ] +} \ No newline at end of file diff --git a/src/Tests/CloudFlare.NET.Tests/Serialization/ErrorResponseSerializationSpec.cs b/src/Tests/CloudFlare.NET.Tests/Serialization/ErrorResponseSerializationSpec.cs new file mode 100644 index 0000000..1c0fb27 --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/Serialization/ErrorResponseSerializationSpec.cs @@ -0,0 +1,32 @@ +namespace CloudFlare.NET.Serialization +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Machine.Specifications; + using Newtonsoft.Json.Linq; + + [Subject(typeof(CloudFlareResponseBase))] + public class When_deserializing_error_response + { + static JObject _errorResponseJson; + static CloudFlareResponseBase _errorResponse; + + Because of = () => + { + _errorResponseJson = SampleJson.ErrorResponse; + _errorResponse = _errorResponseJson.ToObject(); + }; + + It should_deserialize_success = + () => _errorResponse.Success.ShouldEqual(_errorResponseJson["success"].Value()); + + It should_deserialize_errors = + () => _errorResponse.Errors + .ShouldContainOnly(_errorResponseJson["errors"].ToObject>()); + + It should_deserialize_messages = + () => _errorResponse.Messages + .ShouldContainOnly(_errorResponseJson["messages"].ToObject>()); + } +} diff --git a/src/Tests/CloudFlare.NET.Tests/Serialization/SampleJson.cs b/src/Tests/CloudFlare.NET.Tests/Serialization/SampleJson.cs new file mode 100644 index 0000000..8b3c8c3 --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/Serialization/SampleJson.cs @@ -0,0 +1,34 @@ +namespace CloudFlare.NET.Serialization +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using Newtonsoft.Json.Linq; + + internal class SampleJson + { + public static JObject Load(string fileName) + { + Stream stream = + typeof(SampleJson).Assembly.GetManifestResourceStream(typeof(SampleJson), $"{fileName}.json"); + + if (stream == null) + throw new InvalidOperationException( + $"Unable to load Sample JSON file '{fileName}'" + + " - did you mark the file as an 'embedded resource'?"); + + using (var sr = new StreamReader(stream)) + { + string json = sr.ReadToEnd(); + return JObject.Parse(json); + } + } + + public static JObject ErrorResponse => Load(nameof(ErrorResponse)); + + public static JObject SuccessResponse => Load(nameof(SuccessResponse)); + + public static JObject Zone => Load(nameof(Zone)); + } +} diff --git a/src/Tests/CloudFlare.NET.Tests/Serialization/SuccessResponse.json b/src/Tests/CloudFlare.NET.Tests/Serialization/SuccessResponse.json new file mode 100644 index 0000000..e3afab8 --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/Serialization/SuccessResponse.json @@ -0,0 +1,26 @@ +{ + "result": { + "id": "2d4d028de3015345da9420df5514dad0", + "type": "A", + "name": "blog.example.com", + "content": "2.6.4.5", + "proxiable": true, + "proxied": false, + "ttl": 1, + "priority": 0, + "locked": false, + "zone_id": "cd7d068de3012345da9420df9514dad0", + "zone_name": "example.com", + "modified_on": "2014-05-28T18:46:18.764425Z", + "created_on": "2014-05-28T18:46:18.764425Z" + }, + "success": true, + "errors": [], + "messages": [], + "result_info": { + "page": 1, + "per_page": 20, + "count": 1, + "total_count": 200 + } +} \ No newline at end of file diff --git a/src/Tests/CloudFlare.NET.Tests/Serialization/SuccessResponseSerializationSpec.cs b/src/Tests/CloudFlare.NET.Tests/Serialization/SuccessResponseSerializationSpec.cs new file mode 100644 index 0000000..e0928cd --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/Serialization/SuccessResponseSerializationSpec.cs @@ -0,0 +1,51 @@ +namespace CloudFlare.NET.Serialization +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Machine.Specifications; + using Newtonsoft.Json.Linq; + + [Subject(typeof(CloudFlareResponse<>))] + public class When_deserializing_success_response + { + static JObject _successResponseJson; + static CloudFlareResponse _successResponse; + + Because of = () => + { + _successResponseJson = SampleJson.SuccessResponse; + _successResponse = _successResponseJson.ToObject>(); + }; + + It should_deserialize_result = + () => _successResponse.Result["id"].ShouldEqual(_successResponseJson["result"]["id"]); + + It should_deserialize_success = + () => _successResponse.Success.ShouldEqual(_successResponseJson["success"].Value()); + + It should_deserialize_errors = + () => _successResponse.Errors + .ShouldContainOnly(_successResponseJson["errors"].ToObject>()); + + It should_deserialize_messages = + () => _successResponse.Messages + .ShouldContainOnly(_successResponseJson["messages"].ToObject>()); + + It should_deserialize_result_info_page = + () => _successResponse.ResultInfo.Page + .ShouldEqual(_successResponseJson["result_info"]["page"].Value()); + + It should_deserialize_result_info_per_page = + () => _successResponse.ResultInfo.PerPage + .ShouldEqual(_successResponseJson["result_info"]["per_page"].Value()); + + It should_deserialize_result_info_count = + () => _successResponse.ResultInfo.Count + .ShouldEqual(_successResponseJson["result_info"]["count"].Value()); + + It should_deserialize_result_info_total_count = + () => _successResponse.ResultInfo.TotalCount + .ShouldEqual(_successResponseJson["result_info"]["total_count"].Value()); + } +} diff --git a/src/Tests/CloudFlare.NET.Tests/Serialization/Zone.json b/src/Tests/CloudFlare.NET.Tests/Serialization/Zone.json new file mode 100644 index 0000000..3dbabc8 --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/Serialization/Zone.json @@ -0,0 +1,69 @@ +{ + "id": "9a7806061c88ada191ed06f989cc3dac", + "name": "example.com", + "development_mode": 7200, + "original_name_servers": [ + "ns1.originaldnshost.com", + "ns2.originaldnshost.com" + ], + "original_registrar": "GoDaddy", + "original_dnshost": "NameCheap", + "created_on": "2014-01-01T05:20:00.12345Z", + "modified_on": "2014-01-01T05:20:00.12345Z", + "name_servers": [ + "tony.ns.cloudflare.com", + "woz.ns.cloudflare.com" + ], + "owner": { + "id": "9a7806061c88ada191ed06f989cc3dac", + "email": "user@example.com", + "owner_type": "user" + }, + "permissions": [ + "#zone:read", + "#zone:edit" + ], + "plan": { + "id": "9a7806061c88ada191ed06f989cc3dac", + "name": "Pro Plan", + "price": 20, + "currency": "USD", + "frequency": "monthly", + "legacy_id": "pro", + "is_subscribed": true, + "can_subscribe": true + }, + "plan_pending": { + "id": "9a7806061c88ada191ed06f989cc3dac", + "name": "Pro Plan", + "price": 20, + "currency": "USD", + "frequency": "monthly", + "legacy_id": "pro", + "is_subscribed": true, + "can_subscribe": true + }, + "status": "active", + "paused": false, + "type": "full", + "checked_on": "2014-01-01T05:20:00.12345Z", + "host": { + "name": "Example Host", + "website": "http://www.examplehost.com" + }, + "vanity_name_servers": [ + "ns1.example.com", + "ns2.example.com" + ], + "betas": [ + "new_feature" + ], + "deactivation_reason": "abuse_violation", + "meta": { + "custom_certificate_quota": 1, + "page_rule_quota": 5, + "wildcard_proxiable": false, + "phishing_detected": false, + "multiple_railgun_connections": false + } +} \ No newline at end of file diff --git a/src/Tests/CloudFlare.NET.Tests/Serialization/ZoneSerializationSpec.cs b/src/Tests/CloudFlare.NET.Tests/Serialization/ZoneSerializationSpec.cs new file mode 100644 index 0000000..b36ffb3 --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/Serialization/ZoneSerializationSpec.cs @@ -0,0 +1,47 @@ +namespace CloudFlare.NET.Serialization +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Machine.Specifications; + using Newtonsoft.Json.Linq; + + [Subject(typeof(Zone))] + public class When_deserializing_zone + { + static JObject _zoneJson; + static Zone _zone; + + Because of = () => + { + _zoneJson = SampleJson.Zone; + _zone = _zoneJson.ToObject(); + }; + + It should_deserialize_id = () => _zone.Id.ToString().ShouldEqual(_zoneJson["id"].Value()); + + It should_deserialize_name = () => _zone.Name.ShouldEqual(_zoneJson["name"].Value()); + + It should_deserialize_development_mode = + () => _zone.DevelopmentMode.ShouldEqual(_zoneJson["development_mode"].Value()); + + It should_deserialize_original_name_servers = + () => _zone.OriginalNameServers + .ShouldContainOnly(_zoneJson["original_name_servers"].ToObject>()); + + It should_deserialize_original_registrar = + () => _zone.OriginalRegistrar.ShouldEqual(_zoneJson["original_registrar"].Value()); + + It should_deserialize_original_dnshost = + () => _zone.OriginalDnshost.ShouldEqual(_zoneJson["original_dnshost"].Value()); + + It should_deserialize_created_on = + () => _zone.CreatedOn.ShouldEqual(_zoneJson["created_on"].Value()); + + It should_deserialize_modified_on = + () => _zone.ModifiedOn.ShouldEqual(_zoneJson["modified_on"].Value()); + + It should_deserialize_name_servers = + () => _zone.NameServers.ShouldContainOnly(_zoneJson["name_servers"].ToObject>()); + } +} diff --git a/src/Tests/CloudFlare.NET.Tests/ZoneClientExtensionsSpec.cs b/src/Tests/CloudFlare.NET.Tests/ZoneClientExtensionsSpec.cs new file mode 100644 index 0000000..3c8e64e --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/ZoneClientExtensionsSpec.cs @@ -0,0 +1,37 @@ +namespace CloudFlare.NET.ZoneSpec +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading; + using System.Threading.Tasks; + using Machine.Specifications; + using Moq; + using Ploeh.AutoFixture; + using MoqIt = Moq.It; + using It = Machine.Specifications.It; + + [Subject(typeof(ZoneClientExtensions))] + public class When_getting_zones : FixtureContext + { + static Mock _zoneClientMock; + static CloudFlareAuth _auth; + static IReadOnlyList _expected; + static IReadOnlyList _actual; + + Establish context = () => + { + _zoneClientMock = _fixture.Create>(); + _auth = _fixture.Create(); + _expected = _fixture.Create(); + _zoneClientMock + .Setup(c => c.GetZonesAsync(CancellationToken.None, _auth)) + .ReturnsAsync(_expected); + }; + + Because of = () => _actual = _zoneClientMock.Object.GetZonesAsync(_auth).Await().AsTask.Result; + + It should_return_the_zones = () => _actual.ShouldBeTheSameAs(_expected); + } +} diff --git a/src/Tests/CloudFlare.NET.Tests/app.config b/src/Tests/CloudFlare.NET.Tests/app.config index 6c22bfb..931d5bf 100644 --- a/src/Tests/CloudFlare.NET.Tests/app.config +++ b/src/Tests/CloudFlare.NET.Tests/app.config @@ -8,7 +8,7 @@ - + diff --git a/src/Tests/CloudFlare.NET.Tests/packages.config b/src/Tests/CloudFlare.NET.Tests/packages.config index 0105069..dc49f3c 100644 --- a/src/Tests/CloudFlare.NET.Tests/packages.config +++ b/src/Tests/CloudFlare.NET.Tests/packages.config @@ -13,8 +13,10 @@ + + From 923ae70716f8839d029701d71ebe68b26a4e50d0 Mon Sep 17 00:00:00 2001 From: James Skimming Date: Mon, 3 Aug 2015 16:15:47 +0100 Subject: [PATCH 2/2] Added integration tests --- src/CloudFlare.NET/Zone.cs | 22 ++--- .../CloudFlare.NET.IntegrationTests.csproj | 88 ++++++++++++++++++ ...re.NET.IntegrationTests.csproj.DotSettings | 8 ++ ...are.NET.IntegrationTests.v2.ncrunchproject | Bin 0 -> 2836 bytes .../CloudFlare.NET.IntegrationTests/Helper.cs | 30 ++++++ .../Properties/AssemblyInfo.cs | 36 +++++++ .../ZonesSpec.cs | 25 +++++ .../app.config | 15 +++ .../packages.config | 8 ++ .../CloudFlare.NET.Tests.csproj | 1 + .../Serialization/SampleJson.cs | 2 + .../Serialization/ZoneMinimal.json | 4 + .../Serialization/ZoneSerializationSpec.cs | 17 ++++ src/cloudflare.net.sln | 7 ++ 14 files changed, 249 insertions(+), 14 deletions(-) create mode 100644 src/Tests/CloudFlare.NET.IntegrationTests/CloudFlare.NET.IntegrationTests.csproj create mode 100644 src/Tests/CloudFlare.NET.IntegrationTests/CloudFlare.NET.IntegrationTests.csproj.DotSettings create mode 100644 src/Tests/CloudFlare.NET.IntegrationTests/CloudFlare.NET.IntegrationTests.v2.ncrunchproject create mode 100644 src/Tests/CloudFlare.NET.IntegrationTests/Helper.cs create mode 100644 src/Tests/CloudFlare.NET.IntegrationTests/Properties/AssemblyInfo.cs create mode 100644 src/Tests/CloudFlare.NET.IntegrationTests/ZonesSpec.cs create mode 100644 src/Tests/CloudFlare.NET.IntegrationTests/app.config create mode 100644 src/Tests/CloudFlare.NET.IntegrationTests/packages.config create mode 100644 src/Tests/CloudFlare.NET.Tests/Serialization/ZoneMinimal.json diff --git a/src/CloudFlare.NET/Zone.cs b/src/CloudFlare.NET/Zone.cs index 0329b1a..46c22e3 100644 --- a/src/CloudFlare.NET/Zone.cs +++ b/src/CloudFlare.NET/Zone.cs @@ -11,7 +11,7 @@ /// public class Zone { - private static readonly IReadOnlyList EmptyString = Enumerable.Empty().ToList(); + private static readonly IReadOnlyList EmptyStrings = Enumerable.Empty().ToArray(); /// /// Initializes a new instance of the class. @@ -20,33 +20,27 @@ public Zone( IdentifierTag id, string name, int developmentMode, - IReadOnlyList originalNameServers, - string originalRegistrar, - string originalDnshost, DateTimeOffset createdOn, DateTimeOffset modifiedOn, + IReadOnlyList originalNameServers = null, + string originalRegistrar = null, + string originalDnshost = null, IReadOnlyList nameServers = null) { if (id == null) throw new ArgumentNullException(nameof(id)); if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name)); - if (originalNameServers == null) - throw new ArgumentNullException(nameof(originalNameServers)); - if (string.IsNullOrWhiteSpace(originalRegistrar)) - throw new ArgumentNullException(nameof(originalRegistrar)); - if (string.IsNullOrWhiteSpace(originalDnshost)) - throw new ArgumentNullException(nameof(originalDnshost)); Id = id; Name = name; DevelopmentMode = developmentMode; - OriginalNameServers = originalNameServers; - OriginalRegistrar = originalRegistrar; - OriginalDnshost = originalDnshost; + OriginalNameServers = originalNameServers ?? EmptyStrings; + OriginalRegistrar = originalRegistrar ?? string.Empty; + OriginalDnshost = originalDnshost ?? string.Empty; CreatedOn = createdOn; ModifiedOn = modifiedOn; - NameServers = nameServers ?? EmptyString; + NameServers = nameServers ?? EmptyStrings; } /// diff --git a/src/Tests/CloudFlare.NET.IntegrationTests/CloudFlare.NET.IntegrationTests.csproj b/src/Tests/CloudFlare.NET.IntegrationTests/CloudFlare.NET.IntegrationTests.csproj new file mode 100644 index 0000000..a460320 --- /dev/null +++ b/src/Tests/CloudFlare.NET.IntegrationTests/CloudFlare.NET.IntegrationTests.csproj @@ -0,0 +1,88 @@ + + + + + Debug + AnyCPU + {B6869F85-BD98-418D-89F7-7E15BB9F1240} + Library + Properties + CloudFlare.NET + CloudFlare.NET.IntegrationTests + v4.6 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\packages\Machine.Specifications.0.9.3\lib\net45\Machine.Specifications.dll + True + + + ..\..\packages\Machine.Specifications.0.9.3\lib\net45\Machine.Specifications.Clr4.dll + True + + + ..\..\packages\Machine.Specifications.Should.0.7.2\lib\net45\Machine.Specifications.Should.dll + True + + + + + + + + ..\..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll + True + + + ..\..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll + True + + + + + + + + + + + + + {895ae2d8-6602-406e-b2ed-7ca9bc3174a5} + CloudFlare.NET + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/src/Tests/CloudFlare.NET.IntegrationTests/CloudFlare.NET.IntegrationTests.csproj.DotSettings b/src/Tests/CloudFlare.NET.IntegrationTests/CloudFlare.NET.IntegrationTests.csproj.DotSettings new file mode 100644 index 0000000..0063a2a --- /dev/null +++ b/src/Tests/CloudFlare.NET.IntegrationTests/CloudFlare.NET.IntegrationTests.csproj.DotSettings @@ -0,0 +1,8 @@ + + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + False + True + True + True \ No newline at end of file diff --git a/src/Tests/CloudFlare.NET.IntegrationTests/CloudFlare.NET.IntegrationTests.v2.ncrunchproject b/src/Tests/CloudFlare.NET.IntegrationTests/CloudFlare.NET.IntegrationTests.v2.ncrunchproject new file mode 100644 index 0000000000000000000000000000000000000000..fc511e5b893a1ed49ff5aa80b3d00b569240808d GIT binary patch literal 2836 zcmb_e%TD7!5bX0x`~!cma6x;BB6)!WhZPYC;>;Q+7-AdQ6COXmOI1&XwqpnE1X-5s zndz?T_x%4il8Ka3$b%#ji<47)=Q5X67P7+5E!I+98_R+GkV8Bp`Hj6)mU5@k+%NI( z#Oi zkiEqjo+kEpX>Ib%p+5yLvb<21^j8ermF_%aXNI?eH!5X60V~>&;@qN><^DR2Bcqvs zO##%q-X7ib-L6`UM+6RJ@gir4Yz{UVJP>PC=sllj4s01c=G{G3V|o1W6ZckFV=VXA z*2QcJT%X@Vcr~-knC+&mix+)EA4Tf7CH%+isam;X*xMyc{{^xy*Q#NL-m6B+WvC$L zFl)}&KUbFccX)|D#+SunA3etA3bD<#dnC0kaW1SM@@QMzN20C2fF?H(;d2?o@Ky2* zPZnDJ^i}ALPNrCk@vs+E=uIoFh)r+qs>4{Y3(-bKC|i54*)=yY`$-r=;OHYWg}uxq z-_I^#SsSfcBg5qlyIuo{oXaaLjA3b*N;B}F)y$WAmJX3Kv@>X8*0Uq|dS*wu)T}IF zsqbh_q`oqSLjU`T!78u!jrIhrbjoy1ySlaCqtO`BCdQCC>ptdL@HMmD!QUtANq?k0 zx}S_;Tq9=n+V>No`{uzJFy#DplnE?i&!1~2%wR>A?)E9u$ZRfbvxd56C0 zHGX}{G + /// Gets the setting my the . + /// + /// The name of the setting. + /// The setting my the . + public static string GetSetting(string name) + { + if (name == null) + throw new ArgumentNullException(nameof(name)); + + return ("True".Equals(Environment.GetEnvironmentVariable("APPVEYOR"), StringComparison.OrdinalIgnoreCase) + ? Environment.GetEnvironmentVariable(name) + : ConfigurationManager.AppSettings[name]) + ?? string.Empty; + } + } +} diff --git a/src/Tests/CloudFlare.NET.IntegrationTests/Properties/AssemblyInfo.cs b/src/Tests/CloudFlare.NET.IntegrationTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e526de1 --- /dev/null +++ b/src/Tests/CloudFlare.NET.IntegrationTests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CloudFlare.NET.IntegrationTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CloudFlare.NET.IntegrationTests")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b6869f85-bd98-418d-89f7-7e15bb9f1240")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Tests/CloudFlare.NET.IntegrationTests/ZonesSpec.cs b/src/Tests/CloudFlare.NET.IntegrationTests/ZonesSpec.cs new file mode 100644 index 0000000..2bc28c1 --- /dev/null +++ b/src/Tests/CloudFlare.NET.IntegrationTests/ZonesSpec.cs @@ -0,0 +1,25 @@ +namespace CloudFlare.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Machine.Specifications; + + [Subject("Zones")] + public class ZonesSpec + { + static ICloudFlareClient _client; + static CloudFlareAuth _auth; + static IReadOnlyList _zones; + + Establish context = () => + { + _client = new CloudFlareClient(); + _auth = new CloudFlareAuth(Helper.AuthEmail, Helper.AuthKey); + }; + + Because of = () => _zones = _client.GetZonesAsync(_auth).Await().AsTask.Result; + + It should_return_the_zones = () => _zones.ShouldNotBeEmpty(); + } +} diff --git a/src/Tests/CloudFlare.NET.IntegrationTests/app.config b/src/Tests/CloudFlare.NET.IntegrationTests/app.config new file mode 100644 index 0000000..d0b54db --- /dev/null +++ b/src/Tests/CloudFlare.NET.IntegrationTests/app.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Tests/CloudFlare.NET.IntegrationTests/packages.config b/src/Tests/CloudFlare.NET.IntegrationTests/packages.config new file mode 100644 index 0000000..2162fcf --- /dev/null +++ b/src/Tests/CloudFlare.NET.IntegrationTests/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/Tests/CloudFlare.NET.Tests/CloudFlare.NET.Tests.csproj b/src/Tests/CloudFlare.NET.Tests/CloudFlare.NET.Tests.csproj index 0942aa6..df0a0b0 100644 --- a/src/Tests/CloudFlare.NET.Tests/CloudFlare.NET.Tests.csproj +++ b/src/Tests/CloudFlare.NET.Tests/CloudFlare.NET.Tests.csproj @@ -119,6 +119,7 @@ + diff --git a/src/Tests/CloudFlare.NET.Tests/Serialization/SampleJson.cs b/src/Tests/CloudFlare.NET.Tests/Serialization/SampleJson.cs index 8b3c8c3..1d735a6 100644 --- a/src/Tests/CloudFlare.NET.Tests/Serialization/SampleJson.cs +++ b/src/Tests/CloudFlare.NET.Tests/Serialization/SampleJson.cs @@ -30,5 +30,7 @@ public static JObject Load(string fileName) public static JObject SuccessResponse => Load(nameof(SuccessResponse)); public static JObject Zone => Load(nameof(Zone)); + + public static JObject ZoneMinimal => Load(nameof(ZoneMinimal)); } } diff --git a/src/Tests/CloudFlare.NET.Tests/Serialization/ZoneMinimal.json b/src/Tests/CloudFlare.NET.Tests/Serialization/ZoneMinimal.json new file mode 100644 index 0000000..6a9f0f2 --- /dev/null +++ b/src/Tests/CloudFlare.NET.Tests/Serialization/ZoneMinimal.json @@ -0,0 +1,4 @@ +{ + "id": "9a7806061c88ada191ed06f989cc3dac", + "name": "example.com" +} \ No newline at end of file diff --git a/src/Tests/CloudFlare.NET.Tests/Serialization/ZoneSerializationSpec.cs b/src/Tests/CloudFlare.NET.Tests/Serialization/ZoneSerializationSpec.cs index b36ffb3..a638459 100644 --- a/src/Tests/CloudFlare.NET.Tests/Serialization/ZoneSerializationSpec.cs +++ b/src/Tests/CloudFlare.NET.Tests/Serialization/ZoneSerializationSpec.cs @@ -44,4 +44,21 @@ public class When_deserializing_zone It should_deserialize_name_servers = () => _zone.NameServers.ShouldContainOnly(_zoneJson["name_servers"].ToObject>()); } + + [Subject(typeof(Zone))] + public class When_deserializing_zone_minimal + { + static JObject _zoneJson; + static Zone _zone; + + Because of = () => + { + _zoneJson = SampleJson.ZoneMinimal; + _zone = _zoneJson.ToObject(); + }; + + It should_deserialize_id = () => _zone.Id.ToString().ShouldEqual(_zoneJson["id"].Value()); + + It should_deserialize_name = () => _zone.Name.ShouldEqual(_zoneJson["name"].Value()); + } } diff --git a/src/cloudflare.net.sln b/src/cloudflare.net.sln index 8f69675..4db2a69 100644 --- a/src/cloudflare.net.sln +++ b/src/cloudflare.net.sln @@ -9,6 +9,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{872E03EB EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudFlare.NET.Tests", "Tests\CloudFlare.NET.Tests\CloudFlare.NET.Tests.csproj", "{33243227-AB2D-45FE-ABD3-2473A50CFD9B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudFlare.NET.IntegrationTests", "Tests\CloudFlare.NET.IntegrationTests\CloudFlare.NET.IntegrationTests.csproj", "{B6869F85-BD98-418D-89F7-7E15BB9F1240}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -23,11 +25,16 @@ Global {33243227-AB2D-45FE-ABD3-2473A50CFD9B}.Debug|Any CPU.Build.0 = Debug|Any CPU {33243227-AB2D-45FE-ABD3-2473A50CFD9B}.Release|Any CPU.ActiveCfg = Release|Any CPU {33243227-AB2D-45FE-ABD3-2473A50CFD9B}.Release|Any CPU.Build.0 = Release|Any CPU + {B6869F85-BD98-418D-89F7-7E15BB9F1240}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6869F85-BD98-418D-89F7-7E15BB9F1240}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6869F85-BD98-418D-89F7-7E15BB9F1240}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6869F85-BD98-418D-89F7-7E15BB9F1240}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {33243227-AB2D-45FE-ABD3-2473A50CFD9B} = {872E03EB-A9C9-45C8-9644-8442B9CF5C4F} + {B6869F85-BD98-418D-89F7-7E15BB9F1240} = {872E03EB-A9C9-45C8-9644-8442B9CF5C4F} EndGlobalSection EndGlobal