Added ZoneTransfer implementation
This commit is contained in:
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Additional articles for the documentation.
|
- Additional articles for the documentation.
|
||||||
- `DateTime` extensions for ISO 8601 formatting.
|
- `DateTime` extensions for ISO 8601 formatting.
|
||||||
- DNS Analytics
|
- DNS Analytics
|
||||||
|
- Zone Transfers
|
||||||
|
|
||||||
|
|
||||||
## [v0.1.0], [zones/v0.1.0], [dns/v0.1.0] - 2025-08-05
|
## [v0.1.0], [zones/v0.1.0], [dns/v0.1.0] - 2025-08-05
|
||||||
|
|||||||
584
src/Extensions/Cloudflare.Dns/DnsZoneTransfersExtensions.cs
Normal file
584
src/Extensions/Cloudflare.Dns/DnsZoneTransfersExtensions.cs
Normal file
@@ -0,0 +1,584 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns.Internals;
|
||||||
|
|
||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extensions for <see href="https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/">DNS Zone Transfers</see>.
|
||||||
|
/// </summary>
|
||||||
|
public static class DnsZoneTransfersExtensions
|
||||||
|
{
|
||||||
|
#region ACLs
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create ACL.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<ACL>> CreateACL(this ICloudflareClient client, CreateACLRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.AccountId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
if (request.IpRangeBaseAddress.AddressFamily == AddressFamily.InterNetwork && request.IpRangeSubnet < 24)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.IpRange), "CIDRs are limited to a maximum of /24 for IPv4.");
|
||||||
|
|
||||||
|
if (request.IpRangeBaseAddress.AddressFamily == AddressFamily.InterNetworkV6 && request.IpRangeSubnet < 64)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.IpRange), "CIDRs are limited to a maximum of /64 for IPv6.");
|
||||||
|
|
||||||
|
var req = new InternalDnsZoneTransferAclRequest
|
||||||
|
{
|
||||||
|
Name = request.Name,
|
||||||
|
IpRange = request.IpRange
|
||||||
|
};
|
||||||
|
|
||||||
|
return client.PostAsync<ACL, InternalDnsZoneTransferAclRequest>($"/accounts/{request.AccountId}/secondary_dns/acls", req, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete ACL.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="aclId">The access control list identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<Identifier>> DeleteACL(this ICloudflareClient client, string accountId, string aclId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
accountId.ValidateCloudflareId();
|
||||||
|
aclId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.DeleteAsync<Identifier>($"/accounts/{accountId}/secondary_dns/acls/{aclId}", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get ACL.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="aclId">The access control list identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<ACL>> ACLDetails(this ICloudflareClient client, string accountId, string aclId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
accountId.ValidateCloudflareId();
|
||||||
|
aclId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.GetAsync<ACL>($"/accounts/{accountId}/secondary_dns/acls/{aclId}", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List ACLs.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<IReadOnlyCollection<ACL>>> ListACLs(this ICloudflareClient client, string accountId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
accountId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.GetAsync<IReadOnlyCollection<ACL>>($"/accounts/{accountId}/secondary_dns/acls", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update ACL.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<ACL>> UpdateACL(this ICloudflareClient client, UpdateDnsZoneTransferAclRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.AccountId.ValidateCloudflareId();
|
||||||
|
request.AclId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
if (request.IpRangeBaseAddress.AddressFamily == AddressFamily.InterNetwork && request.IpRangeSubnet < 24)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.IpRange), "CIDRs are limited to a maximum of /24 for IPv4.");
|
||||||
|
|
||||||
|
if (request.IpRangeBaseAddress.AddressFamily == AddressFamily.InterNetworkV6 && request.IpRangeSubnet < 64)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.IpRange), "CIDRs are limited to a maximum of /64 for IPv6.");
|
||||||
|
|
||||||
|
var req = new InternalDnsZoneTransferAclRequest
|
||||||
|
{
|
||||||
|
Name = request.Name,
|
||||||
|
IpRange = request.IpRange
|
||||||
|
};
|
||||||
|
|
||||||
|
return client.PutAsync<ACL, InternalDnsZoneTransferAclRequest>($"/accounts/{request.AccountId}/secondary_dns/acls/{request.AclId}", req, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion ACLs
|
||||||
|
|
||||||
|
#region Force AXFR
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends AXFR zone transfer request to primary nameserver(s).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<string>> ForceAXFR(this ICloudflareClient client, string zoneId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.PostAsync<string, object>($"/zones/{zoneId}/secondary_dns/force_axfr", null, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Force AXFR
|
||||||
|
|
||||||
|
#region Incoming
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create secondary zone configuration for incoming zone transfers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<IncomingZoneConfiguration>> CreateSecondaryZoneConfiguration(this ICloudflareClient client, SecondaryZoneConfigurationRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.ZoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(request.Name))
|
||||||
|
throw new ArgumentNullException(nameof(request.Name), "The zone name is required.");
|
||||||
|
|
||||||
|
if (request.AutoRefreshSeconds < 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.AutoRefreshSeconds), "Auto refresh seconds must be greater than or equal to 0.");
|
||||||
|
|
||||||
|
if (request.Peers.Count == 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.Peers), "At least one peer is required.");
|
||||||
|
|
||||||
|
foreach (string peer in request.Peers)
|
||||||
|
peer.ValidateCloudflareId();
|
||||||
|
|
||||||
|
var req = new InternalSecondaryZoneConfigurationRequest
|
||||||
|
{
|
||||||
|
Name = request.Name,
|
||||||
|
AutoRefreshSeconds = request.AutoRefreshSeconds,
|
||||||
|
Peers = request.Peers.ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
return client.PostAsync<IncomingZoneConfiguration, InternalSecondaryZoneConfigurationRequest>($"/zones/{request.ZoneId}/secondary_dns/incoming", req, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete secondary zone configuration for incoming zone transfers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<Identifier>> DeleteSecondaryZoneConfiguration(this ICloudflareClient client, string zoneId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.DeleteAsync<Identifier>($"/zones/{zoneId}/secondary_dns/incoming", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get secondary zone configuration for incoming zone transfers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<IncomingZoneConfiguration>> SecondaryZoneConfigurationDetails(this ICloudflareClient client, string zoneId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.GetAsync<IncomingZoneConfiguration>($"/zones/{zoneId}/secondary_dns/incoming", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update secondary zone configuration for incoming zone transfers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<IncomingZoneConfiguration>> UpdateSecondaryZoneConfiguration(this ICloudflareClient client, SecondaryZoneConfigurationRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.ZoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(request.Name))
|
||||||
|
throw new ArgumentNullException(nameof(request.Name), "The zone name is required.");
|
||||||
|
|
||||||
|
if (request.AutoRefreshSeconds < 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.AutoRefreshSeconds), "Auto refresh seconds must be greater than or equal to 0.");
|
||||||
|
|
||||||
|
if (request.Peers.Count == 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.Peers), "At least one peer is required.");
|
||||||
|
|
||||||
|
foreach (string peer in request.Peers)
|
||||||
|
peer.ValidateCloudflareId();
|
||||||
|
|
||||||
|
var req = new InternalSecondaryZoneConfigurationRequest
|
||||||
|
{
|
||||||
|
Name = request.Name,
|
||||||
|
AutoRefreshSeconds = request.AutoRefreshSeconds,
|
||||||
|
Peers = request.Peers.ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
return client.PutAsync<IncomingZoneConfiguration, InternalSecondaryZoneConfigurationRequest>($"/zones/{request.ZoneId}/secondary_dns/incoming", req, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Incoming
|
||||||
|
|
||||||
|
#region Outgoing
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create primary zone configuration for outgoing zone transfers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<OutgoingZoneConfiguration>> CreatePrimaryZoneConfiguration(this ICloudflareClient client, PrimaryZoneConfigurationRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.ZoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(request.Name))
|
||||||
|
throw new ArgumentNullException(nameof(request.Name), "The zone name is required.");
|
||||||
|
|
||||||
|
if (request.Peers.Count == 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.Peers), "At least one peer is required.");
|
||||||
|
|
||||||
|
foreach (string peer in request.Peers)
|
||||||
|
peer.ValidateCloudflareId();
|
||||||
|
|
||||||
|
var req = new InternalPrimaryZoneConfigurationRequest
|
||||||
|
{
|
||||||
|
Name = request.Name,
|
||||||
|
Peers = request.Peers.ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
return client.PostAsync<OutgoingZoneConfiguration, InternalPrimaryZoneConfigurationRequest>($"/zones/{request.ZoneId}/secondary_dns/outgoing", req, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete primary zone configuration for outgoing zone transfers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<Identifier>> DeletePrimaryZoneConfiguration(this ICloudflareClient client, string zoneId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.DeleteAsync<Identifier>($"/zones/{zoneId}/secondary_dns/outgoing", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disable outgoing zone transfers for primary zone and clears IXFR backlog of primary zone.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// Referring to the
|
||||||
|
/// <see href="https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/outgoing/methods/disable/">documentation</see>,
|
||||||
|
/// the text value should be <em>Disabled</em>.
|
||||||
|
/// </returns>
|
||||||
|
public static Task<CloudflareResponse<string>> DisableOutgoingZoneTransfers(this ICloudflareClient client, string zoneId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.PostAsync<string, object>($"/zones/{zoneId}/secondary_dns/outgoing/disable", null, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable outgoing zone transfers for primary zone.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// Referring to the
|
||||||
|
/// <see href="https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/outgoing/methods/enable/">documentation</see>,
|
||||||
|
/// the text value should be <em>Enabled</em>.
|
||||||
|
/// </returns>
|
||||||
|
public static Task<CloudflareResponse<string>> EnableOutgoingZoneTransfers(this ICloudflareClient client, string zoneId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.PostAsync<string, object>($"/zones/{zoneId}/secondary_dns/outgoing/enable", null, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get primary zone configuration for outgoing zone transfers
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<OutgoingZoneConfiguration>> PrimaryZoneConfigurationDetails(this ICloudflareClient client, string zoneId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.GetAsync<OutgoingZoneConfiguration>($"/zones/{zoneId}/secondary_dns/outgoing", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update primary zone configuration for outgoing zone transfers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<OutgoingZoneConfiguration>> UpdatePrimaryZoneConfiguration(this ICloudflareClient client, PrimaryZoneConfigurationRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.ZoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(request.Name))
|
||||||
|
throw new ArgumentNullException(nameof(request.Name), "The zone name is required.");
|
||||||
|
|
||||||
|
if (request.Peers.Count == 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.Peers), "At least one peer is required.");
|
||||||
|
|
||||||
|
foreach (string peer in request.Peers)
|
||||||
|
peer.ValidateCloudflareId();
|
||||||
|
|
||||||
|
var req = new InternalPrimaryZoneConfigurationRequest
|
||||||
|
{
|
||||||
|
Name = request.Name,
|
||||||
|
Peers = request.Peers.ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
return client.PutAsync<OutgoingZoneConfiguration, InternalPrimaryZoneConfigurationRequest>($"/zones/{request.ZoneId}/secondary_dns/outgoing", req, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Notifies the secondary nameserver(s) and clears IXFR backlog of primary zone.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// Referring to the
|
||||||
|
/// <see href="https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/outgoing/methods/force_notify/">documentation</see>,
|
||||||
|
/// the text value should be <em>OK</em>.
|
||||||
|
/// </returns>
|
||||||
|
public static Task<CloudflareResponse<string>> ForceDNSNotify(this ICloudflareClient client, string zoneId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.PostAsync<string, object>($"/zones/{zoneId}/secondary_dns/outgoing/force_notify", null, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable outgoing zone transfers for primary zone.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// Referring to the
|
||||||
|
/// <see href="https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/outgoing/subresources/status/methods/get/">documentation</see>,
|
||||||
|
/// the text value should be <em>Enabled</em> or <em>Disabled</em>.
|
||||||
|
/// </returns>
|
||||||
|
public static Task<CloudflareResponse<string>> GetOutgoingZoneTransferStatus(this ICloudflareClient client, string zoneId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
zoneId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.GetAsync<string>($"/zones/{zoneId}/secondary_dns/outgoing/status", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Outgoing
|
||||||
|
|
||||||
|
#region Peers
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List Peers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<IReadOnlyCollection<Peer>>> ListPeers(this ICloudflareClient client, string accountId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
accountId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.GetAsync<IReadOnlyCollection<Peer>>($"/accounts/{accountId}/secondary_dns/peers", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get Peer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="peerId">The peer identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<Peer>> PeerDetails(this ICloudflareClient client, string accountId, string peerId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
accountId.ValidateCloudflareId();
|
||||||
|
peerId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.GetAsync<Peer>($"/accounts/{accountId}/secondary_dns/peers/{peerId}", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create Peer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<Peer>> CreatePeer(this ICloudflareClient client, CreatePeerRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.AccountId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(request.Name))
|
||||||
|
throw new ArgumentNullException(nameof(request.Name), "The peer name is required.");
|
||||||
|
|
||||||
|
var req = new InternalCreatePeerRequest
|
||||||
|
{
|
||||||
|
Name = request.Name
|
||||||
|
};
|
||||||
|
|
||||||
|
return client.PostAsync<Peer, InternalCreatePeerRequest>($"/accounts/{request.AccountId}/secondary_dns/peers", req, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Modify Peer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<Peer>> UpdatePeer(this ICloudflareClient client, UpdatePeerRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.AccountId.ValidateCloudflareId();
|
||||||
|
request.PeerId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(request.Name))
|
||||||
|
throw new ArgumentNullException(nameof(request.Name), "The peer name is required.");
|
||||||
|
|
||||||
|
if (request.Port < 0 || 65535 < request.Port)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.Port), "The port must be between 0 and 65535.");
|
||||||
|
|
||||||
|
var req = new InternalUpdatePeerRequest
|
||||||
|
{
|
||||||
|
Name = request.Name,
|
||||||
|
Ip = request.IpAddress,
|
||||||
|
IxfrEnable = request.IXFREnable,
|
||||||
|
Port = request.Port,
|
||||||
|
TSigId = request.TSIGId
|
||||||
|
};
|
||||||
|
|
||||||
|
return client.PutAsync<Peer, InternalUpdatePeerRequest>($"/accounts/{request.AccountId}/secondary_dns/peers/{request.PeerId}", req, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete Peer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="peerId">The peer identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<Identifier>> DeletePeer(this ICloudflareClient client, string accountId, string peerId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
accountId.ValidateCloudflareId();
|
||||||
|
peerId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.DeleteAsync<Identifier>($"/accounts/{accountId}/secondary_dns/peers/{peerId}", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Peers
|
||||||
|
|
||||||
|
#region TSIGs
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List TSIGs.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<IReadOnlyCollection<TSIG>>> ListTSIGs(this ICloudflareClient client, string accountId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
accountId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.GetAsync<IReadOnlyCollection<TSIG>>($"/accounts/{accountId}/secondary_dns/tsigs", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get TSIG.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="tsigId">The TSIG identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<TSIG>> TSIGDetails(this ICloudflareClient client, string accountId, string tsigId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
accountId.ValidateCloudflareId();
|
||||||
|
tsigId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.GetAsync<TSIG>($"/accounts/{accountId}/secondary_dns/tsigs/{tsigId}", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create TSIG.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<TSIG>> CreateTSIG(this ICloudflareClient client, CreateTSIGRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.AccountId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(request.Name))
|
||||||
|
throw new ArgumentNullException(nameof(request.Name), "The TSIG name is required.");
|
||||||
|
|
||||||
|
if (!Enum.IsDefined(typeof(TSigAlgorithm), request.Algorithm))
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.Algorithm), "The TSIG algorithm is invalid.");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(request.Secret))
|
||||||
|
throw new ArgumentNullException(nameof(request.Secret), "The TSIG secret is required.");
|
||||||
|
|
||||||
|
var req = new InternalTSIGRequest
|
||||||
|
{
|
||||||
|
Name = request.Name,
|
||||||
|
Algorithm = request.Algorithm,
|
||||||
|
Secret = request.Secret
|
||||||
|
};
|
||||||
|
|
||||||
|
return client.PostAsync<TSIG, InternalTSIGRequest>($"/accounts/{request.AccountId}/secondary_dns/tsigs", req, null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Modify TSIG.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<TSIG>> UpdateTSIG(this ICloudflareClient client, UpdateTSIGRequest request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
request.AccountId.ValidateCloudflareId();
|
||||||
|
request.TSigId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(request.Name))
|
||||||
|
throw new ArgumentNullException(nameof(request.Name), "The TSIG name is required.");
|
||||||
|
|
||||||
|
if (!Enum.IsDefined(typeof(TSigAlgorithm), request.Algorithm))
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(request.Algorithm), "The TSIG algorithm is invalid.");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(request.Secret))
|
||||||
|
throw new ArgumentNullException(nameof(request.Secret), "The TSIG secret is required.");
|
||||||
|
|
||||||
|
var req = new InternalTSIGRequest
|
||||||
|
{
|
||||||
|
Name = request.Name,
|
||||||
|
Algorithm = request.Algorithm,
|
||||||
|
Secret = request.Secret
|
||||||
|
};
|
||||||
|
|
||||||
|
return client.PutAsync<TSIG, InternalTSIGRequest>($"/accounts/{request.AccountId}/secondary_dns/tsigs/{request.TSigId}", req, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete TSIG.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The <see cref="ICloudflareClient"/> instance.</param>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="tsigId">The TSIG identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token used to propagate notification that this operation should be canceled.</param>
|
||||||
|
public static Task<CloudflareResponse<Identifier>> DeleteTSIG(this ICloudflareClient client, string accountId, string tsigId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
accountId.ValidateCloudflareId();
|
||||||
|
tsigId.ValidateCloudflareId();
|
||||||
|
|
||||||
|
return client.DeleteAsync<Identifier>($"/accounts/{accountId}/secondary_dns/tsigs/{tsigId}", null, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion TSIGs
|
||||||
|
}
|
||||||
|
}
|
||||||
100
src/Extensions/Cloudflare.Dns/Enums/TSigAlgorithm.cs
Normal file
100
src/Extensions/Cloudflare.Dns/Enums/TSigAlgorithm.cs
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Available TSIG algorithms as <see href="https://www.rfc-editor.org/rfc/rfc8945.html#section-6">recommended by IANA</see>.
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public enum TSigAlgorithm
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// HMAC SHA1.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Implementation: <strong>must</strong>
|
||||||
|
/// <br/>
|
||||||
|
/// Use: <em>not recommended</em>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "hmac-sha1")]
|
||||||
|
HMAC_SHA1 = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HMAC SHA224.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Implementation: <strong>may</strong>
|
||||||
|
/// <br/>
|
||||||
|
/// Use: <em>may</em>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "hmac-sha224")]
|
||||||
|
HMAC_SHA224 = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HMAC SHA256.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Implementation: <strong>must</strong>
|
||||||
|
/// <br/>
|
||||||
|
/// Use: <em>recommended</em>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "hmac-sha256")]
|
||||||
|
HMAC_SHA256 = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HMAC SHA384.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Implementation: <strong>may</strong>
|
||||||
|
/// <br/>
|
||||||
|
/// Use: <em>may</em>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "hmac-sha384")]
|
||||||
|
HMAC_SHA384 = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HMAC SHA512.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Implementation: <strong>may</strong>
|
||||||
|
/// <br/>
|
||||||
|
/// Use: <em>may</em>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "hmac-sha512")]
|
||||||
|
HMAC_SHA512 = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HMAC SHA256 128.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Implementation: <strong>may</strong>
|
||||||
|
/// <br/>
|
||||||
|
/// Use: <em>may</em>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "hmac-sha256-128")]
|
||||||
|
HMAC_SHA256_128 = 6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HMAC SHA384 192.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Implementation: <strong>may</strong>
|
||||||
|
/// <br/>
|
||||||
|
/// Use: <em>may</em>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "hmac-sha384-192")]
|
||||||
|
HMAC_SHA384_192 = 7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HMAC SHA512 256.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Implementation: <strong>may</strong>
|
||||||
|
/// <br/>
|
||||||
|
/// Use: <em>may</em>
|
||||||
|
/// </remarks>
|
||||||
|
[EnumMember(Value = "hmac-sha512-256")]
|
||||||
|
HMAC_SHA512_256 = 8,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns.Internals
|
||||||
|
{
|
||||||
|
internal class InternalCreatePeerRequest
|
||||||
|
{
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
internal class InternalDnsZoneTransferAclRequest
|
||||||
|
{
|
||||||
|
[JsonProperty("ip_range")]
|
||||||
|
public string? IpRange { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns.Internals
|
||||||
|
{
|
||||||
|
internal class InternalPrimaryZoneConfigurationRequest
|
||||||
|
{
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("peers")]
|
||||||
|
public IReadOnlyCollection<string>? Peers { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns.Internals
|
||||||
|
{
|
||||||
|
internal class InternalSecondaryZoneConfigurationRequest
|
||||||
|
{
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("auto_refresh_seconds")]
|
||||||
|
public int? AutoRefreshSeconds { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("peers")]
|
||||||
|
public IReadOnlyCollection<string>? Peers { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns.Internals
|
||||||
|
{
|
||||||
|
internal class InternalTSIGRequest
|
||||||
|
{
|
||||||
|
[JsonProperty("algo")]
|
||||||
|
public TSigAlgorithm? Algorithm { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("secret")]
|
||||||
|
public string? Secret { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns.Internals
|
||||||
|
{
|
||||||
|
internal class InternalUpdatePeerRequest : InternalCreatePeerRequest
|
||||||
|
{
|
||||||
|
[JsonProperty("ip")]
|
||||||
|
public string? Ip { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("ixfr_enable")]
|
||||||
|
public bool? IxfrEnable { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("port")]
|
||||||
|
public int? Port { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("tsig_id")]
|
||||||
|
public string? TSigId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/Extensions/Cloudflare.Dns/Models/ACL.cs
Normal file
31
src/Extensions/Cloudflare.Dns/Models/ACL.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an Access Control List (ACL) entry, which defines the allowed IP ranges for DNS zone transfers.
|
||||||
|
/// </summary>
|
||||||
|
public class ACL
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The unique identifier.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public string? Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allowed IPv4/IPv6 address range of primary or secondary nameservers.
|
||||||
|
/// This will be applied for the entire account.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The IP range is used to allow additional NOTIFY IPs for secondary zones and IPs Cloudflare allows AXFR/IXFR requests from for primary zones.
|
||||||
|
/// CIDRs are limited to a maximum of /24 for IPv4 and /64 for IPv6 respectively.
|
||||||
|
/// </remarks>
|
||||||
|
[JsonProperty("ip_range")]
|
||||||
|
public string? IpRange { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the ACL.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a response of a secondary zone configuration.
|
||||||
|
/// </summary>
|
||||||
|
public class IncomingZoneConfiguration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The unique identifier.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public string? Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How often should a secondary zone auto refresh regardless of DNS NOTIFY.
|
||||||
|
/// Not applicable for primary zones.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("auto_refresh_seconds")]
|
||||||
|
public int? AutoRefreshSeconds { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time for a specific event.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("checked_time")]
|
||||||
|
public DateTime? CheckedTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time for a specific event.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("created_time")]
|
||||||
|
public DateTime? CreatedTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time for a specific event.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("modified_time")]
|
||||||
|
public DateTime? ModifiedTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The zone name.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of peer tags.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("peers")]
|
||||||
|
public IReadOnlyCollection<string>? Peers { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The serial number of the SOA for the given zone.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("soa_serial")]
|
||||||
|
public int? SoaSerial { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a response of a secondary zone configuration.
|
||||||
|
/// </summary>
|
||||||
|
public class OutgoingZoneConfiguration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The unique identifier.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public string? Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time for a specific event.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("checked_time")]
|
||||||
|
public DateTime? CheckedTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time for a specific event.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("created_time")]
|
||||||
|
public DateTime? CreatedTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time for a specific event.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("last_transferred_time")]
|
||||||
|
public DateTime? LastTransferredTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The zone name.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of peer tags.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("peers")]
|
||||||
|
public IReadOnlyCollection<string>? Peers { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The serial number of the SOA for the given zone.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("soa_serial")]
|
||||||
|
public int? SoaSerial { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
61
src/Extensions/Cloudflare.Dns/Models/Peer.cs
Normal file
61
src/Extensions/Cloudflare.Dns/Models/Peer.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A Cloudflare peer.
|
||||||
|
/// <see href="https://github.com/cloudflare/cloudflare-typescript/blob/v4.4.1/src/resources/dns/zone-transfers/peers.ts#L119">Source</see>
|
||||||
|
/// </summary>
|
||||||
|
public class Peer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Peer"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The unique identifier.</param>
|
||||||
|
/// <param name="name">The name of the peer.</param>
|
||||||
|
public Peer(string id, string name)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The unique identifier.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the peer.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IPv4/IPv6 address of primary or secondary nameserver, depending on what zone this peer is linked to.
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item>For primary zones this IP defines the IP of the secondary nameserver Cloudflare will NOTIFY upon zone changes.</item>
|
||||||
|
/// <item>For secondary zones this IP defines the IP of the primary nameserver Cloudflare will send AXFR/IXFR requests to.</item>
|
||||||
|
/// </list>
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("ip")]
|
||||||
|
public string? IpAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable IXFR transfer protocol, default is AXFR.
|
||||||
|
/// <em>Only applicable to secondary zones.</em>
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("ixfr_enable")]
|
||||||
|
public bool? IXFREnabled { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DNS port of primary or secondary nameserver, depending on what zone this peer is linked to.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("port")]
|
||||||
|
public int? Port { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TSIG authentication will be used for zone transfer if configured.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("tsig_id")]
|
||||||
|
public string? TSIGId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/Extensions/Cloudflare.Dns/Models/TSIG.cs
Normal file
35
src/Extensions/Cloudflare.Dns/Models/TSIG.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Transaction Signature (TSIG) used for securing DNS messages.
|
||||||
|
/// </summary>
|
||||||
|
public class TSIG
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The unique identifier.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public string? Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TSIG algorithm.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("algo")]
|
||||||
|
public TSigAlgorithm? Algorithm { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TSIG key name.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TSIG secret.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("secret")]
|
||||||
|
public string? Secret { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,6 +59,59 @@ This package contains the feature set of the _DNS_ section of the Cloudflare API
|
|||||||
- [Show DNS Settings](https://developers.cloudflare.com/api/resources/dns/subresources/settings/subresources/zone/methods/get/)
|
- [Show DNS Settings](https://developers.cloudflare.com/api/resources/dns/subresources/settings/subresources/zone/methods/get/)
|
||||||
|
|
||||||
|
|
||||||
|
#### [Zone Transfers]
|
||||||
|
|
||||||
|
##### [ACLs]
|
||||||
|
|
||||||
|
- [List ACLs](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/acls/methods/list/)
|
||||||
|
- [ACL Details](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/acls/methods/get/)
|
||||||
|
- [Create ACL](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/acls/methods/create/)
|
||||||
|
- [Update ACL](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/acls/methods/update/)
|
||||||
|
- [Delete ACL](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/acls/methods/delete/)
|
||||||
|
|
||||||
|
|
||||||
|
##### Force AXFR
|
||||||
|
|
||||||
|
- [Force AXFR](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/force_axfr/methods/create/)
|
||||||
|
|
||||||
|
|
||||||
|
##### [Incoming]
|
||||||
|
|
||||||
|
- [Create Secondary Zone Configuration](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/incoming/methods/create/)
|
||||||
|
- [Delete Secondary Zone Configuration](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/incoming/methods/delete/)
|
||||||
|
- [Secondary Zone Configuration Details](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/incoming/methods/get/)
|
||||||
|
- [Update Secondary Zone Configuration](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/incoming/methods/update/)
|
||||||
|
|
||||||
|
|
||||||
|
##### [Outgoing]
|
||||||
|
|
||||||
|
- [Create Primary Zone Configuration](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/outgoing/methods/create/)
|
||||||
|
- [Delete Primary Zone Configuration](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/outgoing/methods/delete/)
|
||||||
|
- [Disable Outgoing Zone Transfers](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/outgoing/methods/disable/)
|
||||||
|
- [Enable Outgoing Zone Transfers](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/outgoing/methods/enable/)
|
||||||
|
- [Primary Zone Configuration Details](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/outgoing/methods/get/)
|
||||||
|
- [Update Primary Zone Configuration](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/outgoing/methods/update/)
|
||||||
|
- [Force DNS Notify](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/outgoing/methods/force_notify/)
|
||||||
|
- [Get Outgoing Zone Transfer Status](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/outgoing/subresources/status/methods/get/)
|
||||||
|
|
||||||
|
|
||||||
|
##### [Peers]
|
||||||
|
|
||||||
|
- [List Peers](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/peers/methods/list/)
|
||||||
|
- [Peer Details](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/peers/methods/get/)
|
||||||
|
- [Create Peer](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/peers/methods/create/)
|
||||||
|
- [Update Peer](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/peers/methods/update/)
|
||||||
|
- [Delete Peer](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/peers/methods/delete/)
|
||||||
|
|
||||||
|
|
||||||
|
##### [TSIGs] (Transaction SIGnatures)
|
||||||
|
|
||||||
|
- [List TSIGs](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/tsigs/methods/list/)
|
||||||
|
- [TSIG Details](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/tsigs/methods/get/)
|
||||||
|
- [Create TSIG](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/tsigs/methods/create/)
|
||||||
|
- [Update TSIG](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/tsigs/methods/update/)
|
||||||
|
- [Delete TSIG](https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/tsigs/methods/delete/)
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -77,3 +130,9 @@ Published under MIT License (see [choose a license])
|
|||||||
[Settings]: https://developers.cloudflare.com/api/resources/dns/subresources/settings/
|
[Settings]: https://developers.cloudflare.com/api/resources/dns/subresources/settings/
|
||||||
[Account]: https://developers.cloudflare.com/api/resources/dns/subresources/settings/subresources/account/
|
[Account]: https://developers.cloudflare.com/api/resources/dns/subresources/settings/subresources/account/
|
||||||
[Zone]: https://developers.cloudflare.com/api/resources/dns/subresources/settings/subresources/zone/
|
[Zone]: https://developers.cloudflare.com/api/resources/dns/subresources/settings/subresources/zone/
|
||||||
|
[Zone Transfers]: https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/
|
||||||
|
[ACLs]: https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/acls/
|
||||||
|
[Incoming]: https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/incoming/
|
||||||
|
[Outgoing]: https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/outgoing/
|
||||||
|
[Peers]: https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/peers/
|
||||||
|
[TSIGs]: https://developers.cloudflare.com/api/resources/dns/subresources/zone_transfers/subresources/tsigs/
|
||||||
|
|||||||
77
src/Extensions/Cloudflare.Dns/Requests/CreateACLRequest.cs
Normal file
77
src/Extensions/Cloudflare.Dns/Requests/CreateACLRequest.cs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
|
||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to create a DNS zone transfer access control list (ACL).
|
||||||
|
/// </summary>
|
||||||
|
public class CreateACLRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CreateACLRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="ipRange">Allowed IPv4/IPv6 address range of primary or secondary nameservers (CIDR).</param>
|
||||||
|
/// <param name="name">The name of the ACL.</param>
|
||||||
|
public CreateACLRequest(string accountId, string ipRange, string name)
|
||||||
|
{
|
||||||
|
IpRangeBaseAddress = IPAddress.None;
|
||||||
|
IpRangeSubnet = 0;
|
||||||
|
|
||||||
|
AccountId = accountId;
|
||||||
|
IpRange = ipRange;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The account identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string AccountId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allowed IPv4/IPv6 address range of primary or secondary nameservers.
|
||||||
|
/// This will be applied for the entire account.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The IP range is used to allow additional NOTIFY IPs for secondary zones and IPs Cloudflare allows AXFR/IXFR requests from for primary zones.
|
||||||
|
/// CIDRs are limited to a maximum of /24 for IPv4 and /64 for IPv6 respectively.
|
||||||
|
/// </remarks>
|
||||||
|
public string IpRange
|
||||||
|
{
|
||||||
|
get => $"{IpRangeBaseAddress}/{IpRangeSubnet}";
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
throw new ArgumentNullException(nameof(value), $"{nameof(IpRange)} cannot be null or empty.");
|
||||||
|
|
||||||
|
string[] parts = value.Split('/');
|
||||||
|
if (parts.Length != 2)
|
||||||
|
throw new FormatException("Invalid IP range format.");
|
||||||
|
|
||||||
|
var prefix = IPAddress.Parse(parts[0]);
|
||||||
|
|
||||||
|
if (!int.TryParse(parts[1], out int prefixLength))
|
||||||
|
throw new FormatException("Invalid IP range subnet format.");
|
||||||
|
|
||||||
|
if (prefix.AddressFamily == AddressFamily.InterNetwork && (prefixLength < 0 || 32 < prefixLength))
|
||||||
|
throw new FormatException("Invalid subnet length for IPv4.");
|
||||||
|
|
||||||
|
if (prefix.AddressFamily == AddressFamily.InterNetworkV6 && (prefixLength < 0 || 128 < prefixLength))
|
||||||
|
throw new FormatException("Invalid subnet length for IPv6.");
|
||||||
|
|
||||||
|
IpRangeBaseAddress = prefix;
|
||||||
|
IpRangeSubnet = prefixLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the ACL.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
internal IPAddress IpRangeBaseAddress { get; set; }
|
||||||
|
|
||||||
|
internal int IpRangeSubnet { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/Extensions/Cloudflare.Dns/Requests/CreatePeerRequest.cs
Normal file
29
src/Extensions/Cloudflare.Dns/Requests/CreatePeerRequest.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to create a new peer within a specific account.
|
||||||
|
/// </summary>
|
||||||
|
public class CreatePeerRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CreatePeerRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="name">The name of the peer.</param>
|
||||||
|
public CreatePeerRequest(string accountId, string name)
|
||||||
|
{
|
||||||
|
AccountId = accountId;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The account identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string AccountId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the peer.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/Extensions/Cloudflare.Dns/Requests/CreateTSIGRequest.cs
Normal file
43
src/Extensions/Cloudflare.Dns/Requests/CreateTSIGRequest.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to create a TSIG (Transaction Signature) key for DNS operations.
|
||||||
|
/// </summary>
|
||||||
|
public class CreateTSIGRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CreateTSIGRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="name">TSIG key name.</param>
|
||||||
|
/// <param name="secret">TSIG secret.</param>
|
||||||
|
public CreateTSIGRequest(string accountId, string name, string secret)
|
||||||
|
{
|
||||||
|
Algorithm = TSigAlgorithm.HMAC_SHA256;
|
||||||
|
|
||||||
|
AccountId = accountId;
|
||||||
|
Name = name;
|
||||||
|
Secret = secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The account identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string AccountId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TSIG algorithm.
|
||||||
|
/// </summary>
|
||||||
|
public TSigAlgorithm Algorithm { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TSIG key name.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TSIG secret.
|
||||||
|
/// </summary>
|
||||||
|
public string Secret { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to create a primary zone configuration.
|
||||||
|
/// </summary>
|
||||||
|
public class PrimaryZoneConfigurationRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="PrimaryZoneConfigurationRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="name">The zone name.</param>
|
||||||
|
public PrimaryZoneConfigurationRequest(string zoneId, string name)
|
||||||
|
{
|
||||||
|
ZoneId = zoneId;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The zone identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string ZoneId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The zone name.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of peer tags.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyCollection<string> Peers { get; set; } = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to create a secondary zone configuration.
|
||||||
|
/// </summary>
|
||||||
|
public class SecondaryZoneConfigurationRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SecondaryZoneConfigurationRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="zoneId">The zone identifier.</param>
|
||||||
|
/// <param name="name">The zone name.</param>
|
||||||
|
public SecondaryZoneConfigurationRequest(string zoneId, string name)
|
||||||
|
{
|
||||||
|
ZoneId = zoneId;
|
||||||
|
Name = name;
|
||||||
|
|
||||||
|
Peers = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The zone identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string ZoneId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Zone name.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How often should a secondary zone auto refresh regardless of DNS NOTIFY. Not applicable for primary zones.
|
||||||
|
/// </summary>
|
||||||
|
public int AutoRefreshSeconds { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of peer tags.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyCollection<string> Peers { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to update an existing DNS zone transfer access control list (ACL).
|
||||||
|
/// </summary>
|
||||||
|
public class UpdateDnsZoneTransferAclRequest : CreateACLRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UpdateDnsZoneTransferAclRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="aclId">The access control list identifier.</param>
|
||||||
|
/// <param name="ipRange">Allowed IPv4/IPv6 address range of primary or secondary nameservers (CIDR).</param>
|
||||||
|
/// <param name="name">The name of the ACL.</param>
|
||||||
|
public UpdateDnsZoneTransferAclRequest(string accountId, string aclId, string ipRange, string name)
|
||||||
|
: base(accountId, ipRange, name)
|
||||||
|
{
|
||||||
|
AclId = aclId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The access control list identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string AclId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/Extensions/Cloudflare.Dns/Requests/UpdatePeerRequest.cs
Normal file
49
src/Extensions/Cloudflare.Dns/Requests/UpdatePeerRequest.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to update an existing peer with new configuration details.
|
||||||
|
/// </summary>
|
||||||
|
public class UpdatePeerRequest : CreatePeerRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UpdatePeerRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="peerId">The peer identifier.</param>
|
||||||
|
/// <param name="name">The name of the peer</param>
|
||||||
|
public UpdatePeerRequest(string accountId, string peerId, string name)
|
||||||
|
: base(accountId, name)
|
||||||
|
{
|
||||||
|
PeerId = peerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The peer identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string PeerId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IPv4/IPv6 address of primary or secondary nameserver, depending on what zone this peer is linked to.
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item>For primary zones this IP defines the IP of the secondary nameserver Cloudflare will NOTIFY upon zone changes.</item>
|
||||||
|
/// <item>For secondary zones this IP defines the IP of the primary nameserver Cloudflare will send AXFR/IXFR requests to.</item>
|
||||||
|
/// </list>
|
||||||
|
/// </summary>
|
||||||
|
public string? IpAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable IXFR transfer protocol, default is AXFR. Only applicable to secondary zones.
|
||||||
|
/// </summary>
|
||||||
|
public bool? IXFREnable { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DNS port of primary or secondary nameserver, depending on what zone this peer is linked to.
|
||||||
|
/// </summary>
|
||||||
|
public int? Port { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TSIG authentication will be used for zone transfer if configured.
|
||||||
|
/// </summary>
|
||||||
|
public string? TSIGId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/Extensions/Cloudflare.Dns/Requests/UpdateTSIGRequest.cs
Normal file
26
src/Extensions/Cloudflare.Dns/Requests/UpdateTSIGRequest.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace AMWD.Net.Api.Cloudflare.Dns
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to update an existing TSIG (Transaction Signature) key.
|
||||||
|
/// </summary>
|
||||||
|
public class UpdateTSIGRequest : CreateTSIGRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UpdateTSIGRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="accountId">The account identifier.</param>
|
||||||
|
/// <param name="tsigId">The TSIG identifier.</param>
|
||||||
|
/// <param name="name">TSIG key name.</param>
|
||||||
|
/// <param name="secret">TSIG secret.</param>
|
||||||
|
public UpdateTSIGRequest(string accountId, string tsigId, string name, string secret)
|
||||||
|
: base(accountId, name, secret)
|
||||||
|
{
|
||||||
|
TSigId = tsigId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The TSIG identifier.
|
||||||
|
/// </summary>
|
||||||
|
public string TSigId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.ACLs
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ACLDetailsTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string AclId = "23ff594956f20c2a721606e94745a8aa";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<ACL> _response;
|
||||||
|
private List<string> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<ACL>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [new ResponseInfo(1000, "Error 1")],
|
||||||
|
Result = new ACL
|
||||||
|
{
|
||||||
|
Id = AclId,
|
||||||
|
IpRange = "192.0.2.0/24",
|
||||||
|
Name = "Test ACL"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldGetAclDetails()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ACLDetails(AccountId, AclId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
string requestPath = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/acls/{AclId}", requestPath);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.GetAsync<ACL>($"/accounts/{AccountId}/secondary_dns/acls/{AclId}", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.GetAsync<ACL>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, _, _) => _callbacks.Add(requestPath))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.ACLs
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class CreateACLTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<ACL> _response;
|
||||||
|
private List<(string RequestPath, InternalDnsZoneTransferAclRequest Request)> _callbacks;
|
||||||
|
private CreateACLRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<ACL>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = new ACL
|
||||||
|
{
|
||||||
|
Id = "23ff594956f20c2a721606e94745a8aa",
|
||||||
|
IpRange = "192.0.2.53/28",
|
||||||
|
Name = "my-acl-1"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new CreateACLRequest(
|
||||||
|
accountId: AccountId,
|
||||||
|
ipRange: "192.0.2.53/28",
|
||||||
|
name: "my-acl-1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldCreateAcl()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.CreateACL(_request, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, request) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/acls", requestPath);
|
||||||
|
|
||||||
|
Assert.IsNotNull(request);
|
||||||
|
Assert.AreEqual(_request.Name, request.Name);
|
||||||
|
Assert.AreEqual(_request.IpRange, request.IpRange);
|
||||||
|
|
||||||
|
Assert.AreEqual("192.0.2.53", _request.IpRangeBaseAddress.ToString());
|
||||||
|
Assert.AreEqual(28, _request.IpRangeSubnet);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<ACL, InternalDnsZoneTransferAclRequest>($"/accounts/{AccountId}/secondary_dns/acls", It.IsAny<InternalDnsZoneTransferAclRequest>(), null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow("127.0.0.1/20")]
|
||||||
|
[DataRow("fd00::/56")]
|
||||||
|
public async Task ShouldThrowArumentOutOfRangeExceptionForWrongSubnetDefinition(string ipRange)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.IpRange = ipRange;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () =>
|
||||||
|
{
|
||||||
|
await client.CreateACL(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow("\t")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public void ShouldThrowArgumentNullExceptionForIpRange(string ipRange)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.ThrowsExactly<ArgumentNullException>(() =>
|
||||||
|
{
|
||||||
|
_ = new CreateACLRequest(AccountId, ipRange, "my-acl-1");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow("192.0.2.53")]
|
||||||
|
[DataRow("192.0.2.53/28/28")]
|
||||||
|
public void ShouldThrowFormatExceptionForInvalidFormat(string ipRange)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.ThrowsExactly<FormatException>(() =>
|
||||||
|
{
|
||||||
|
_ = new CreateACLRequest(AccountId, ipRange, "my-acl-1");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ShouldThrowFormatExceptionForInvalidSubnetFormat()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.ThrowsExactly<FormatException>(() =>
|
||||||
|
{
|
||||||
|
_ = new CreateACLRequest(AccountId, "192.0.2.53/a", "my-acl-1");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow("127.0.0.1/-1")]
|
||||||
|
[DataRow("127.0.0.1/33")]
|
||||||
|
[DataRow("fd00::/-1")]
|
||||||
|
[DataRow("fd00::/129")]
|
||||||
|
public void ShouldThrowFormatExceptionForInvalidSubnetLength(string ipRange)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.ThrowsExactly<FormatException>(() =>
|
||||||
|
{
|
||||||
|
_ = new CreateACLRequest(AccountId, ipRange, "my-acl-1");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PostAsync<ACL, InternalDnsZoneTransferAclRequest>(It.IsAny<string>(), It.IsAny<InternalDnsZoneTransferAclRequest>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, InternalDnsZoneTransferAclRequest, IQueryParameterFilter, CancellationToken>((requestPath, request, _, _) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.ACLs
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class DeleteACLTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string AclId = "23ff594956f20c2a721606e94745a8aa";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<Identifier> _response;
|
||||||
|
private List<string> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = new List<string>();
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<Identifier>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [new ResponseInfo(1000, "Error 1")],
|
||||||
|
Result = new Identifier
|
||||||
|
{
|
||||||
|
Id = AclId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldDeleteAcl()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.DeleteACL(AccountId, AclId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
string requestPath = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/acls/{AclId}", requestPath);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.DeleteAsync<Identifier>($"/accounts/{AccountId}/secondary_dns/acls/{AclId}", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.DeleteAsync<Identifier>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, _, _) => _callbacks.Add(requestPath))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.ACLs
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ListACLsTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<IReadOnlyCollection<ACL>> _response;
|
||||||
|
private List<string> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = new List<string>();
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<IReadOnlyCollection<ACL>>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = new List<ResponseInfo> { new ResponseInfo(1000, "Message 1") },
|
||||||
|
Errors = new List<ResponseInfo> { new ResponseInfo(1000, "Error 1") },
|
||||||
|
Result = new List<ACL>
|
||||||
|
{
|
||||||
|
new ACL
|
||||||
|
{
|
||||||
|
Id = "23ff594956f20c2a721606e94745a8aa",
|
||||||
|
IpRange = "192.0.2.0/24",
|
||||||
|
Name = "Test ACL"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldListAcls()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ListACLs(AccountId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
string requestPath = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/acls", requestPath);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.GetAsync<IReadOnlyCollection<ACL>>($"/accounts/{AccountId}/secondary_dns/acls", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.GetAsync<IReadOnlyCollection<ACL>>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, _, _) => _callbacks.Add(requestPath))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.ACLs
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class UpdateACLTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string AclId = "23ff594956f20c2a721606e94745a8aa";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<ACL> _response;
|
||||||
|
private List<(string RequestPath, InternalDnsZoneTransferAclRequest Request)> _callbacks;
|
||||||
|
private UpdateDnsZoneTransferAclRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<ACL>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = new ACL
|
||||||
|
{
|
||||||
|
Id = AclId,
|
||||||
|
IpRange = "192.0.2.53/28",
|
||||||
|
Name = "my-acl-1"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new UpdateDnsZoneTransferAclRequest(
|
||||||
|
accountId: AccountId,
|
||||||
|
aclId: AclId,
|
||||||
|
ipRange: "192.0.2.53/28",
|
||||||
|
name: "my-acl-1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldUpdateAcl()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.UpdateACL(_request, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, request) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/acls/{AclId}", requestPath);
|
||||||
|
|
||||||
|
Assert.IsNotNull(request);
|
||||||
|
Assert.AreEqual(_request.Name, request.Name);
|
||||||
|
Assert.AreEqual(_request.IpRange, request.IpRange);
|
||||||
|
|
||||||
|
Assert.AreEqual("192.0.2.53", _request.IpRangeBaseAddress.ToString());
|
||||||
|
Assert.AreEqual(28, _request.IpRangeSubnet);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PutAsync<ACL, InternalDnsZoneTransferAclRequest>($"/accounts/{AccountId}/secondary_dns/acls/{AclId}", It.IsAny<InternalDnsZoneTransferAclRequest>(), TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow("127.0.0.1/20")]
|
||||||
|
[DataRow("fd00::/56")]
|
||||||
|
public async Task ShouldThrowArumentOutOfRangeExceptionForWrongSubnetDefinition(string ipRange)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.IpRange = ipRange;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () =>
|
||||||
|
{
|
||||||
|
await client.UpdateACL(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PutAsync<ACL, InternalDnsZoneTransferAclRequest>(It.IsAny<string>(), It.IsAny<InternalDnsZoneTransferAclRequest>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, InternalDnsZoneTransferAclRequest, CancellationToken>((requestPath, request, _) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ForceAXFRTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<string> _response;
|
||||||
|
private List<(string RequestPath, object Request)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<string>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = "OK"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldForceAXFR()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ForceAXFR(ZoneId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, request) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/secondary_dns/force_axfr", requestPath);
|
||||||
|
|
||||||
|
Assert.IsNull(request);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<string, object>($"/zones/{ZoneId}/secondary_dns/force_axfr", null, null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PostAsync<string, object>(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, object, IQueryParameterFilter, CancellationToken>((requestPath, request, _, _) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns.Internals;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Incoming
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class CreateSecondaryZoneConfigurationTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string PeerId = "23ff594956f20c2a721606e94745a8aa";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<IncomingZoneConfiguration> _response;
|
||||||
|
private List<(string RequestPath, InternalSecondaryZoneConfigurationRequest Request)> _callbacks;
|
||||||
|
private SecondaryZoneConfigurationRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<IncomingZoneConfiguration>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [new ResponseInfo(1000, "Error 1")],
|
||||||
|
Result = new IncomingZoneConfiguration
|
||||||
|
{
|
||||||
|
Id = "269d8f4853475ca241c4e730be286b20",
|
||||||
|
Name = "www.example.com",
|
||||||
|
AutoRefreshSeconds = 86400,
|
||||||
|
Peers = [PeerId]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new SecondaryZoneConfigurationRequest(ZoneId, "www.example.com")
|
||||||
|
{
|
||||||
|
AutoRefreshSeconds = 86400,
|
||||||
|
Peers = [PeerId]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldCreateSecondaryZoneConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.CreateSecondaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, request) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/secondary_dns/incoming", requestPath);
|
||||||
|
Assert.IsNotNull(request);
|
||||||
|
|
||||||
|
Assert.AreEqual(_request.Name, request.Name);
|
||||||
|
Assert.AreEqual(_request.AutoRefreshSeconds, request.AutoRefreshSeconds);
|
||||||
|
CollectionAssert.AreEqual(_request.Peers.ToList(), request.Peers.ToList());
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<IncomingZoneConfiguration, InternalSecondaryZoneConfigurationRequest>(
|
||||||
|
$"/zones/{ZoneId}/secondary_dns/incoming",
|
||||||
|
It.IsAny<InternalSecondaryZoneConfigurationRequest>(),
|
||||||
|
null,
|
||||||
|
It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public async Task ShouldThrowArgumentNullExceptionForName(string name)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Name = name;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentNullException>(async () =>
|
||||||
|
{
|
||||||
|
await client.CreateSecondaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldThrowArgumentOutOfRangeExceptionForAutoRefreshSeconds()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.AutoRefreshSeconds = -1;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () =>
|
||||||
|
{
|
||||||
|
await client.CreateSecondaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldThrowArgumentOutOfRangeExceptionForEmptyPeers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Peers = [];
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () =>
|
||||||
|
{
|
||||||
|
await client.CreateSecondaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldThrowArgumentExceptionForInvalidPeerId()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Peers = ["invalid-peer-id"]; // invalid format
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentException>(async () =>
|
||||||
|
{
|
||||||
|
await client.CreateSecondaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PostAsync<IncomingZoneConfiguration, InternalSecondaryZoneConfigurationRequest>(
|
||||||
|
It.IsAny<string>(),
|
||||||
|
It.IsAny<InternalSecondaryZoneConfigurationRequest>(),
|
||||||
|
It.IsAny<IQueryParameterFilter>(),
|
||||||
|
It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, InternalSecondaryZoneConfigurationRequest, IQueryParameterFilter, CancellationToken>((requestPath, request, _, __) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Incoming
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class DeleteSecondaryZoneConfigurationTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<Identifier> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = new List<(string, IQueryParameterFilter)>();
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<Identifier>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = new List<ResponseInfo> { new ResponseInfo(1000, "Message 1") },
|
||||||
|
Errors = new List<ResponseInfo>(),
|
||||||
|
Result = new Identifier { Id = "269d8f4853475ca241c4e730be286b20" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldDeleteSecondaryZoneConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.DeleteSecondaryZoneConfiguration(ZoneId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.IsNotNull(response.Result);
|
||||||
|
Assert.AreEqual("269d8f4853475ca241c4e730be286b20", response.Result.Id);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, queryFilter) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/secondary_dns/incoming", requestPath);
|
||||||
|
Assert.IsNull(queryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.DeleteAsync<Identifier>($"/zones/{ZoneId}/secondary_dns/incoming", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.DeleteAsync<Identifier>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Incoming
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class SecondaryZoneConfigurationDetailsTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string PeerId = "23ff594956f20c2a721606e94745a8aa";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<IncomingZoneConfiguration> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<IncomingZoneConfiguration>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [],
|
||||||
|
Result = new IncomingZoneConfiguration
|
||||||
|
{
|
||||||
|
Id = "269d8f4853475ca241c4e730be286b20",
|
||||||
|
Name = "www.example.com",
|
||||||
|
AutoRefreshSeconds = 86400,
|
||||||
|
Peers = [PeerId]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldGetSecondaryZoneConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.SecondaryZoneConfigurationDetails(ZoneId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.IsNotNull(response.Result);
|
||||||
|
Assert.AreEqual("269d8f4853475ca241c4e730be286b20", response.Result.Id);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, queryFilter) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/secondary_dns/incoming", requestPath);
|
||||||
|
Assert.IsNull(queryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.GetAsync<IncomingZoneConfiguration>($"/zones/{ZoneId}/secondary_dns/incoming", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.GetAsync<IncomingZoneConfiguration>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns.Internals;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Incoming
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class UpdateSecondaryZoneConfigurationTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string PeerId = "23ff594956f20c2a721606e94745a8aa";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<IncomingZoneConfiguration> _response;
|
||||||
|
private List<(string RequestPath, InternalSecondaryZoneConfigurationRequest Request)> _callbacks;
|
||||||
|
private SecondaryZoneConfigurationRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<IncomingZoneConfiguration>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [new ResponseInfo(1000, "Error 1")],
|
||||||
|
Result = new IncomingZoneConfiguration
|
||||||
|
{
|
||||||
|
Id = "269d8f4853475ca241c4e730be286b20",
|
||||||
|
Name = "www.example.com",
|
||||||
|
AutoRefreshSeconds = 86400,
|
||||||
|
Peers = [PeerId]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new SecondaryZoneConfigurationRequest(ZoneId, "www.example.com")
|
||||||
|
{
|
||||||
|
AutoRefreshSeconds = 86400,
|
||||||
|
Peers = [PeerId]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldUpdateSecondaryZoneConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.UpdateSecondaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, request) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/secondary_dns/incoming", requestPath);
|
||||||
|
Assert.IsNotNull(request);
|
||||||
|
|
||||||
|
Assert.AreEqual(_request.Name, request.Name);
|
||||||
|
Assert.AreEqual(_request.AutoRefreshSeconds, request.AutoRefreshSeconds);
|
||||||
|
CollectionAssert.AreEqual(_request.Peers.ToList(), request.Peers.ToList());
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PutAsync<IncomingZoneConfiguration, InternalSecondaryZoneConfigurationRequest>(
|
||||||
|
$"/zones/{ZoneId}/secondary_dns/incoming",
|
||||||
|
It.IsAny<InternalSecondaryZoneConfigurationRequest>(),
|
||||||
|
TestContext.CancellationToken), Times.Once);
|
||||||
|
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public async Task ShouldThrowArgumentNullExceptionForName(string name)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Name = name;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentNullException>(async () =>
|
||||||
|
{
|
||||||
|
await client.UpdateSecondaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldThrowArgumentOutOfRangeExceptionForAutoRefreshSeconds()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.AutoRefreshSeconds = -1;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () =>
|
||||||
|
{
|
||||||
|
await client.UpdateSecondaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldThrowArgumentOutOfRangeExceptionForEmptyPeers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Peers = [];
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () =>
|
||||||
|
{
|
||||||
|
await client.UpdateSecondaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldThrowArgumentExceptionForInvalidPeerId()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Peers = ["invalid-peer-id"]; // invalid format
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentException>(async () =>
|
||||||
|
{
|
||||||
|
await client.UpdateSecondaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PutAsync<IncomingZoneConfiguration, InternalSecondaryZoneConfigurationRequest>(
|
||||||
|
It.IsAny<string>(),
|
||||||
|
It.IsAny<InternalSecondaryZoneConfigurationRequest>(),
|
||||||
|
It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, InternalSecondaryZoneConfigurationRequest, CancellationToken>((requestPath, request, _) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns.Internals;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Outgoing
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class CreatePrimaryZoneConfigurationTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string PeerId = "23ff594956f20c2a721606e94745a8aa";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<OutgoingZoneConfiguration> _response;
|
||||||
|
private List<(string RequestPath, InternalPrimaryZoneConfigurationRequest Request)> _callbacks;
|
||||||
|
private PrimaryZoneConfigurationRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<OutgoingZoneConfiguration>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [new ResponseInfo(1000, "Error 1")],
|
||||||
|
Result = new OutgoingZoneConfiguration
|
||||||
|
{
|
||||||
|
Id = "269d8f4853475ca241c4e730be286b20",
|
||||||
|
Name = "www.example.com",
|
||||||
|
Peers = [PeerId]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new PrimaryZoneConfigurationRequest(ZoneId, "www.example.com")
|
||||||
|
{
|
||||||
|
Peers = [PeerId]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldCreatePrimaryZoneConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.CreatePrimaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, request) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/secondary_dns/outgoing", requestPath);
|
||||||
|
Assert.IsNotNull(request);
|
||||||
|
|
||||||
|
Assert.AreEqual(_request.Name, request.Name);
|
||||||
|
CollectionAssert.AreEqual(_request.Peers.ToList(), request.Peers.ToList());
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<OutgoingZoneConfiguration, InternalPrimaryZoneConfigurationRequest>(
|
||||||
|
$"/zones/{ZoneId}/secondary_dns/outgoing",
|
||||||
|
It.IsAny<InternalPrimaryZoneConfigurationRequest>(),
|
||||||
|
null,
|
||||||
|
TestContext.CancellationToken), Times.Once);
|
||||||
|
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public async Task ShouldThrowArgumentNullExceptionForName(string name)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Name = name;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentNullException>(async () =>
|
||||||
|
{
|
||||||
|
await client.CreatePrimaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldThrowArgumentOutOfRangeExceptionForEmptyPeers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Peers = [];
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () =>
|
||||||
|
{
|
||||||
|
await client.CreatePrimaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldThrowArgumentExceptionForInvalidPeerId()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Peers = ["invalid-peer-id"]; // invalid format
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentException>(async () =>
|
||||||
|
{
|
||||||
|
await client.CreatePrimaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PostAsync<OutgoingZoneConfiguration, InternalPrimaryZoneConfigurationRequest>(
|
||||||
|
It.IsAny<string>(),
|
||||||
|
It.IsAny<InternalPrimaryZoneConfigurationRequest>(),
|
||||||
|
It.IsAny<IQueryParameterFilter>(),
|
||||||
|
It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, InternalPrimaryZoneConfigurationRequest, IQueryParameterFilter, CancellationToken>((requestPath, request, _, __) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Outgoing
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class DeletePrimaryZoneConfigurationTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<Identifier> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<Identifier>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = new List<ResponseInfo> { new(1000, "Message 1") },
|
||||||
|
Errors = [],
|
||||||
|
Result = new Identifier
|
||||||
|
{
|
||||||
|
Id = "269d8f4853475ca241c4e730be286b20"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldDeletePrimaryZoneConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.DeletePrimaryZoneConfiguration(ZoneId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.IsNotNull(response.Result);
|
||||||
|
Assert.AreEqual("269d8f4853475ca241c4e730be286b20", response.Result.Id);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, queryFilter) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/secondary_dns/outgoing", requestPath);
|
||||||
|
Assert.IsNull(queryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.DeleteAsync<Identifier>($"/zones/{ZoneId}/secondary_dns/outgoing", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.DeleteAsync<Identifier>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Outgoing
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class DisableOutgoingZoneTransfersTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<string> _response;
|
||||||
|
private List<(string RequestPath, object Request)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<string>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = "Disabled"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldDisableOutgoingZoneTransfers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.DisableOutgoingZoneTransfers(ZoneId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, request) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/secondary_dns/outgoing/disable", requestPath);
|
||||||
|
Assert.IsNull(request);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<string, object>(
|
||||||
|
$"/zones/{ZoneId}/secondary_dns/outgoing/disable",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PostAsync<string, object>(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, object, IQueryParameterFilter, CancellationToken>((requestPath, request, _, _) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Outgoing
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class EnableOutgoingZoneTransfersTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<string> _response;
|
||||||
|
private List<(string RequestPath, object Request)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<string>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = "Enabled"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldDisableOutgoingZoneTransfers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.EnableOutgoingZoneTransfers(ZoneId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, request) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/secondary_dns/outgoing/enable", requestPath);
|
||||||
|
Assert.IsNull(request);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<string, object>(
|
||||||
|
$"/zones/{ZoneId}/secondary_dns/outgoing/enable",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PostAsync<string, object>(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, object, IQueryParameterFilter, CancellationToken>((requestPath, request, _, _) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Outgoing
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ForceDNSNotifyTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<string> _response;
|
||||||
|
private List<(string RequestPath, object Request)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<string>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [new ResponseInfo(1000, "Error 1")],
|
||||||
|
Result = "OK"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldForceDNSNotify()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ForceDNSNotify(ZoneId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, request) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/secondary_dns/outgoing/force_notify", requestPath);
|
||||||
|
Assert.IsNull(request);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<string, object>(
|
||||||
|
$"/zones/{ZoneId}/secondary_dns/outgoing/force_notify",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
TestContext.CancellationToken), Times.Once);
|
||||||
|
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PostAsync<string, object>(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, object, IQueryParameterFilter, CancellationToken>((requestPath, request, _, _) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Outgoing
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class GetOutgoingZoneTransferStatusTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<string> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<string>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [],
|
||||||
|
Result = "Enabled"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldGetOutgoingZoneTransferStatus()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.GetOutgoingZoneTransferStatus(ZoneId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, queryFilter) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/secondary_dns/outgoing/status", requestPath);
|
||||||
|
Assert.IsNull(queryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.GetAsync<string>($"/zones/{ZoneId}/secondary_dns/outgoing/status", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.GetAsync<string>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Outgoing
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class PrimaryZoneConfigurationDetailsTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string PeerId = "23ff594956f20c2a721606e94745a8aa";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<OutgoingZoneConfiguration> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<OutgoingZoneConfiguration>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [],
|
||||||
|
Result = new OutgoingZoneConfiguration
|
||||||
|
{
|
||||||
|
Id = "269d8f4853475ca241c4e730be286b20",
|
||||||
|
Name = "www.example.com",
|
||||||
|
Peers = [PeerId],
|
||||||
|
SoaSerial = 12345
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldGetPrimaryZoneConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.PrimaryZoneConfigurationDetails(ZoneId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.IsNotNull(response.Result);
|
||||||
|
Assert.AreEqual("269d8f4853475ca241c4e730be286b20", response.Result.Id);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, queryFilter) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/secondary_dns/outgoing", requestPath);
|
||||||
|
Assert.IsNull(queryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.GetAsync<OutgoingZoneConfiguration>($"/zones/{ZoneId}/secondary_dns/outgoing", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.GetAsync<OutgoingZoneConfiguration>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns.Internals;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Outgoing
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class UpdatePrimaryZoneConfigurationTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string ZoneId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string PeerId = "23ff594956f20c2a721606e94745a8aa";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<OutgoingZoneConfiguration> _response;
|
||||||
|
private List<(string RequestPath, InternalPrimaryZoneConfigurationRequest Request)> _callbacks;
|
||||||
|
private PrimaryZoneConfigurationRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<OutgoingZoneConfiguration>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [],
|
||||||
|
Result = new OutgoingZoneConfiguration
|
||||||
|
{
|
||||||
|
Id = "269d8f4853475ca241c4e730be286b20",
|
||||||
|
Name = "www.example.com",
|
||||||
|
Peers = [PeerId],
|
||||||
|
SoaSerial = 12345
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new PrimaryZoneConfigurationRequest(ZoneId, "www.example.com")
|
||||||
|
{
|
||||||
|
Peers = [PeerId]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldUpdatePrimaryZoneConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.UpdatePrimaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.IsNotNull(response.Result);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, req) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/zones/{ZoneId}/secondary_dns/outgoing", requestPath);
|
||||||
|
Assert.IsNotNull(req);
|
||||||
|
|
||||||
|
Assert.AreEqual(_request.Name, req.Name);
|
||||||
|
CollectionAssert.AreEqual(_request.Peers.ToList(), req.Peers.ToList());
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PutAsync<OutgoingZoneConfiguration, InternalPrimaryZoneConfigurationRequest>(
|
||||||
|
$"/zones/{ZoneId}/secondary_dns/outgoing",
|
||||||
|
It.IsAny<InternalPrimaryZoneConfigurationRequest>(),
|
||||||
|
TestContext.CancellationToken), Times.Once);
|
||||||
|
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public async Task ShouldThrowArgumentNullExceptionForName(string name)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Name = name;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentNullException>(async () =>
|
||||||
|
{
|
||||||
|
await client.UpdatePrimaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldThrowArgumentOutOfRangeExceptionForEmptyPeers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Peers = [];
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () =>
|
||||||
|
{
|
||||||
|
await client.UpdatePrimaryZoneConfiguration(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PutAsync<OutgoingZoneConfiguration, InternalPrimaryZoneConfigurationRequest>(
|
||||||
|
It.IsAny<string>(),
|
||||||
|
It.IsAny<InternalPrimaryZoneConfigurationRequest>(),
|
||||||
|
It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, InternalPrimaryZoneConfigurationRequest, CancellationToken>((requestPath, request, _) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns.Internals;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Peers
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class CreatePeerTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<Peer> _response;
|
||||||
|
private List<(string RequestPath, InternalCreatePeerRequest Request)> _callbacks;
|
||||||
|
private CreatePeerRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = new List<(string, InternalCreatePeerRequest)>();
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<Peer>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = new List<ResponseInfo> { new ResponseInfo(1000, "Message 1") },
|
||||||
|
Errors = new List<ResponseInfo>(),
|
||||||
|
Result = new Peer("023e105f4ecef8ad9ca31a8372d0c351", "peer-a")
|
||||||
|
{
|
||||||
|
IpAddress = "192.0.2.1",
|
||||||
|
IXFREnabled = true,
|
||||||
|
Port = 5353,
|
||||||
|
TSIGId = "tsig-1"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new CreatePeerRequest(AccountId, "peer-a");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldCreatePeer()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.CreatePeer(_request, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.IsNotNull(response.Result);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, req) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/peers", requestPath);
|
||||||
|
Assert.IsNotNull(req);
|
||||||
|
Assert.AreEqual(_request.Name, req.Name);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<Peer, InternalCreatePeerRequest>(
|
||||||
|
$"/accounts/{AccountId}/secondary_dns/peers",
|
||||||
|
It.IsAny<InternalCreatePeerRequest>(),
|
||||||
|
null,
|
||||||
|
TestContext.CancellationToken), Times.Once);
|
||||||
|
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public async Task ShouldThrowArgumentNullExceptionForName(string name)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Name = name;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentNullException>(async () =>
|
||||||
|
{
|
||||||
|
await client.CreatePeer(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PostAsync<Peer, InternalCreatePeerRequest>(It.IsAny<string>(), It.IsAny<InternalCreatePeerRequest>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, InternalCreatePeerRequest, IQueryParameterFilter, CancellationToken>((requestPath, request, _, __) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Peers
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class DeletePeerTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string PeerId = "23ff594956f20c2a721606e94745a8aa";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<Identifier> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<Identifier>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [],
|
||||||
|
Result = new Identifier
|
||||||
|
{
|
||||||
|
Id = PeerId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldDeletePeer()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.DeletePeer(AccountId, PeerId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.IsNotNull(response.Result);
|
||||||
|
Assert.AreEqual(PeerId, response.Result.Id);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, queryFilter) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/peers/{PeerId}", requestPath);
|
||||||
|
Assert.IsNull(queryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.DeleteAsync<Identifier>($"/accounts/{AccountId}/secondary_dns/peers/{PeerId}", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.DeleteAsync<Identifier>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Peers
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ListPeersTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<IReadOnlyCollection<Peer>> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<IReadOnlyCollection<Peer>>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [],
|
||||||
|
Result =
|
||||||
|
[
|
||||||
|
new Peer("023e105f4ecef8ad9ca31a8372d0c351", "peer-a")
|
||||||
|
{
|
||||||
|
IpAddress = "192.0.2.1",
|
||||||
|
IXFREnabled = true,
|
||||||
|
Port = 5353,
|
||||||
|
TSIGId = "tsig-1"
|
||||||
|
},
|
||||||
|
new Peer("023e105f4ecef8ad9ca31a8372d0c352", "peer-b")
|
||||||
|
{
|
||||||
|
IpAddress = "2001:db8::1",
|
||||||
|
IXFREnabled = false,
|
||||||
|
Port = 53,
|
||||||
|
TSIGId = null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldListPeers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ListPeers(AccountId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.IsNotNull(response.Result);
|
||||||
|
Assert.HasCount(2, response.Result);
|
||||||
|
|
||||||
|
var peers = response.Result.ToList();
|
||||||
|
Assert.AreEqual("peer-a", peers[0].Name);
|
||||||
|
Assert.AreEqual("192.0.2.1", peers[0].IpAddress);
|
||||||
|
Assert.IsTrue(peers[0].IXFREnabled ?? false);
|
||||||
|
Assert.AreEqual(5353, peers[0].Port);
|
||||||
|
Assert.AreEqual("tsig-1", peers[0].TSIGId);
|
||||||
|
|
||||||
|
Assert.AreEqual("peer-b", peers[1].Name);
|
||||||
|
Assert.AreEqual("2001:db8::1", peers[1].IpAddress);
|
||||||
|
Assert.IsFalse(peers[1].IXFREnabled ?? false);
|
||||||
|
Assert.AreEqual(53, peers[1].Port);
|
||||||
|
Assert.IsNull(peers[1].TSIGId);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
var (requestPath, queryFilter) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/peers", requestPath);
|
||||||
|
Assert.IsNull(queryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.GetAsync<IReadOnlyCollection<Peer>>($"/accounts/{AccountId}/secondary_dns/peers", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.GetAsync<IReadOnlyCollection<Peer>>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Peers
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class PeerDetailsTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string PeerId = "23ff594956f20c2a721606e94745a8aa";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<Peer> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<Peer>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [],
|
||||||
|
Result = new Peer(PeerId, "peer-a")
|
||||||
|
{
|
||||||
|
IpAddress = "192.0.2.1",
|
||||||
|
IXFREnabled = true,
|
||||||
|
Port = 5353,
|
||||||
|
TSIGId = "tsig-1"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldGetPeerDetails()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.PeerDetails(AccountId, PeerId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.IsNotNull(response.Result);
|
||||||
|
Assert.AreEqual(PeerId, response.Result.Id);
|
||||||
|
Assert.AreEqual("peer-a", response.Result.Name);
|
||||||
|
Assert.AreEqual("192.0.2.1", response.Result.IpAddress);
|
||||||
|
Assert.IsTrue(response.Result.IXFREnabled ?? false);
|
||||||
|
Assert.AreEqual(5353, response.Result.Port);
|
||||||
|
Assert.AreEqual("tsig-1", response.Result.TSIGId);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
var (requestPath, queryFilter) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/peers/{PeerId}", requestPath);
|
||||||
|
Assert.IsNull(queryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.GetAsync<Peer>($"/accounts/{AccountId}/secondary_dns/peers/{PeerId}", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.GetAsync<Peer>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns.Internals;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.Peers
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class UpdatePeerTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string PeerId = "23ff594956f20c2a721606e94745a8aa";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<Peer> _response;
|
||||||
|
private List<(string RequestPath, InternalUpdatePeerRequest Request)> _callbacks;
|
||||||
|
private UpdatePeerRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<Peer>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [],
|
||||||
|
Result = new Peer(PeerId, "peer-a")
|
||||||
|
{
|
||||||
|
IpAddress = "192.0.2.1",
|
||||||
|
IXFREnabled = true,
|
||||||
|
Port = 5353,
|
||||||
|
TSIGId = "tsig-1"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new UpdatePeerRequest(AccountId, PeerId, "peer-a")
|
||||||
|
{
|
||||||
|
IpAddress = "192.0.2.1",
|
||||||
|
IXFREnable = true,
|
||||||
|
Port = 5353,
|
||||||
|
TSIGId = "tsig-1"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldUpdatePeer()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.UpdatePeer(_request, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.IsNotNull(response.Result);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
var (requestPath, req) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/peers/{PeerId}", requestPath);
|
||||||
|
|
||||||
|
Assert.IsNotNull(req);
|
||||||
|
Assert.AreEqual(_request.Name, req.Name);
|
||||||
|
Assert.AreEqual(_request.IpAddress, req.Ip);
|
||||||
|
Assert.AreEqual(_request.IXFREnable, req.IxfrEnable);
|
||||||
|
Assert.AreEqual(_request.Port, req.Port);
|
||||||
|
Assert.AreEqual(_request.TSIGId, req.TSigId);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PutAsync<Peer, InternalUpdatePeerRequest>(
|
||||||
|
$"/accounts/{AccountId}/secondary_dns/peers/{PeerId}",
|
||||||
|
It.IsAny<InternalUpdatePeerRequest>(),
|
||||||
|
TestContext.CancellationToken), Times.Once);
|
||||||
|
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public async Task ShouldThrowArgumentNullExceptionForName(string name)
|
||||||
|
{
|
||||||
|
_request.Name = name;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentNullException>(async () =>
|
||||||
|
{
|
||||||
|
await client.UpdatePeer(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldThrowArgumentOutOfRangeExceptionForPortLessThanZero()
|
||||||
|
{
|
||||||
|
_request.Port = -1;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () =>
|
||||||
|
{
|
||||||
|
await client.UpdatePeer(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldThrowArgumentOutOfRangeExceptionForPortGreaterThan65535()
|
||||||
|
{
|
||||||
|
_request.Port = 70000;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () =>
|
||||||
|
{
|
||||||
|
await client.UpdatePeer(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PutAsync<Peer, InternalUpdatePeerRequest>(It.IsAny<string>(), It.IsAny<InternalUpdatePeerRequest>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, InternalUpdatePeerRequest, CancellationToken>((requestPath, request, _) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns.Internals;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.TSIGs
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class CreateTSIGTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<TSIG> _response;
|
||||||
|
private List<(string RequestPath, InternalTSIGRequest Request)> _callbacks;
|
||||||
|
private CreateTSIGRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<TSIG>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors = [
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = new TSIG
|
||||||
|
{
|
||||||
|
Id = "tsig-1",
|
||||||
|
Name = "tsig-key-a",
|
||||||
|
Secret = "very-secret",
|
||||||
|
Algorithm = TSigAlgorithm.HMAC_SHA256
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new CreateTSIGRequest(
|
||||||
|
accountId: AccountId,
|
||||||
|
name: "tsig-key-a",
|
||||||
|
secret: "very-secret"
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Algorithm = TSigAlgorithm.HMAC_SHA512
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldCreateTsig()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.CreateTSIG(_request, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, request) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/tsigs", requestPath);
|
||||||
|
|
||||||
|
Assert.IsNotNull(request);
|
||||||
|
Assert.AreEqual(_request.Name, request.Name);
|
||||||
|
Assert.AreEqual(_request.Secret, request.Secret);
|
||||||
|
Assert.AreEqual(_request.Algorithm, request.Algorithm);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PostAsync<TSIG, InternalTSIGRequest>($"/accounts/{AccountId}/secondary_dns/tsigs", It.IsAny<InternalTSIGRequest>(), null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public async Task ShouldThrowArgumentNullExceptionForName(string name)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Name = name;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentNullException>(async () =>
|
||||||
|
{
|
||||||
|
await client.CreateTSIG(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldThrowArgumentOutOfRangeExceptionForAlgorithm()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Algorithm = 0;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () =>
|
||||||
|
{
|
||||||
|
await client.CreateTSIG(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public async Task ShouldThrowArgumentNullExceptionForSecret(string secret)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Secret = secret;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentNullException>(async () =>
|
||||||
|
{
|
||||||
|
await client.CreateTSIG(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PostAsync<TSIG, InternalTSIGRequest>(It.IsAny<string>(), It.IsAny<InternalTSIGRequest>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, InternalTSIGRequest, IQueryParameterFilter, CancellationToken>((requestPath, request, _, __) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.TSIGs
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class DeleteTSIGTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string TsigId = "023e105f4ecef8ad9ca31a8372d0c351";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<Identifier> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<Identifier>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages =
|
||||||
|
[
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
],
|
||||||
|
Errors =
|
||||||
|
[
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
],
|
||||||
|
Result = new Identifier
|
||||||
|
{
|
||||||
|
Id = TsigId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldDeleteTSIG()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.DeleteTSIG(AccountId, TsigId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.IsNotNull(response.Result);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, queryFilter) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/tsigs/{TsigId}", requestPath);
|
||||||
|
Assert.IsNull(queryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.DeleteAsync<Identifier>($"/accounts/{AccountId}/secondary_dns/tsigs/{TsigId}", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.DeleteAsync<Identifier>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.TSIGs
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ListTSIGsTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<IReadOnlyCollection<TSIG>> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = [];
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<IReadOnlyCollection<TSIG>>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [],
|
||||||
|
Result =
|
||||||
|
[
|
||||||
|
new TSIG
|
||||||
|
{
|
||||||
|
Id = "tsig-1",
|
||||||
|
Name = "tsig-key-a",
|
||||||
|
Secret = "secretA",
|
||||||
|
Algorithm = TSigAlgorithm.HMAC_SHA256
|
||||||
|
},
|
||||||
|
new TSIG
|
||||||
|
{
|
||||||
|
Id = "tsig-2",
|
||||||
|
Name = "tsig-key-b",
|
||||||
|
Secret = "secretB",
|
||||||
|
Algorithm = TSigAlgorithm.HMAC_SHA1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldListTSIGs()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.ListTSIGs(AccountId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.IsNotNull(response.Result);
|
||||||
|
Assert.HasCount(2, response.Result);
|
||||||
|
|
||||||
|
var tsigs = response.Result.ToList();
|
||||||
|
Assert.AreEqual("tsig-key-a", tsigs[0].Name);
|
||||||
|
Assert.AreEqual("secretA", tsigs[0].Secret);
|
||||||
|
Assert.AreEqual(TSigAlgorithm.HMAC_SHA256, tsigs[0].Algorithm);
|
||||||
|
|
||||||
|
Assert.AreEqual("tsig-key-b", tsigs[1].Name);
|
||||||
|
Assert.AreEqual("secretB", tsigs[1].Secret);
|
||||||
|
Assert.AreEqual(TSigAlgorithm.HMAC_SHA1, tsigs[1].Algorithm);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
var (requestPath, queryFilter) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/tsigs", requestPath);
|
||||||
|
Assert.IsNull(queryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.GetAsync<IReadOnlyCollection<TSIG>>($"/accounts/{AccountId}/secondary_dns/tsigs", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.GetAsync<IReadOnlyCollection<TSIG>>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.TSIGs
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class TSIGDetailsTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string TsigId = "023e105f4ecef8ad9ca31a8372d0c351";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<TSIG> _response;
|
||||||
|
private List<(string RequestPath, IQueryParameterFilter QueryFilter)> _callbacks;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = new List<(string, IQueryParameterFilter)>();
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<TSIG>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = [new ResponseInfo(1000, "Message 1")],
|
||||||
|
Errors = [new ResponseInfo(1000, "Error 1")],
|
||||||
|
Result = new TSIG
|
||||||
|
{
|
||||||
|
Id = TsigId,
|
||||||
|
Name = "tsig-key-a",
|
||||||
|
Secret = "very-secret",
|
||||||
|
Algorithm = TSigAlgorithm.HMAC_SHA256
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldGetTSIGDetails()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.TSIGDetails(AccountId, TsigId, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.IsNotNull(response.Result);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, queryFilter) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/tsigs/{TsigId}", requestPath);
|
||||||
|
Assert.IsNull(queryFilter);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.GetAsync<TSIG>($"/accounts/{AccountId}/secondary_dns/tsigs/{TsigId}", null, TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.GetAsync<TSIG>(It.IsAny<string>(), It.IsAny<IQueryParameterFilter>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, IQueryParameterFilter, CancellationToken>((requestPath, queryFilter, _) => _callbacks.Add((requestPath, queryFilter)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AMWD.Net.Api.Cloudflare;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns;
|
||||||
|
using AMWD.Net.Api.Cloudflare.Dns.Internals;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Cloudflare.Dns.Tests.DnsZoneTransfersExtensions.TSIGs
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class UpdateTSIGTest
|
||||||
|
{
|
||||||
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
private const string AccountId = "023e105f4ecef8ad9ca31a8372d0c353";
|
||||||
|
private const string TsigId = "023e105f4ecef8ad9ca31a8372d0c351";
|
||||||
|
|
||||||
|
private Mock<ICloudflareClient> _clientMock;
|
||||||
|
private CloudflareResponse<TSIG> _response;
|
||||||
|
private List<(string RequestPath, InternalTSIGRequest Request)> _callbacks;
|
||||||
|
private UpdateTSIGRequest _request;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_callbacks = new List<(string, InternalTSIGRequest)>();
|
||||||
|
|
||||||
|
_response = new CloudflareResponse<TSIG>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Messages = new[]
|
||||||
|
{
|
||||||
|
new ResponseInfo(1000, "Message 1")
|
||||||
|
},
|
||||||
|
Errors = new[]
|
||||||
|
{
|
||||||
|
new ResponseInfo(1000, "Error 1")
|
||||||
|
},
|
||||||
|
Result = new TSIG
|
||||||
|
{
|
||||||
|
Id = TsigId,
|
||||||
|
Name = "tsig-key-a",
|
||||||
|
Secret = "very-secret",
|
||||||
|
Algorithm = TSigAlgorithm.HMAC_SHA256
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_request = new UpdateTSIGRequest(
|
||||||
|
accountId: AccountId,
|
||||||
|
tsigId: TsigId,
|
||||||
|
name: "tsig-key-a",
|
||||||
|
secret: "very-secret"
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Algorithm = TSigAlgorithm.HMAC_SHA512
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldUpdateTsig()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.UpdateTSIG(_request, TestContext.CancellationToken);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(response);
|
||||||
|
Assert.IsTrue(response.Success);
|
||||||
|
Assert.AreEqual(_response.Result, response.Result);
|
||||||
|
|
||||||
|
Assert.HasCount(1, _callbacks);
|
||||||
|
|
||||||
|
var (requestPath, request) = _callbacks.First();
|
||||||
|
Assert.AreEqual($"/accounts/{AccountId}/secondary_dns/tsigs/{TsigId}", requestPath);
|
||||||
|
|
||||||
|
Assert.IsNotNull(request);
|
||||||
|
Assert.AreEqual(_request.Name, request.Name);
|
||||||
|
Assert.AreEqual(_request.Secret, request.Secret);
|
||||||
|
Assert.AreEqual(_request.Algorithm, request.Algorithm);
|
||||||
|
|
||||||
|
_clientMock.Verify(m => m.PutAsync<TSIG, InternalTSIGRequest>($"/accounts/{AccountId}/secondary_dns/tsigs/{TsigId}", It.IsAny<InternalTSIGRequest>(), TestContext.CancellationToken), Times.Once);
|
||||||
|
_clientMock.VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public async Task ShouldThrowArgumentNullExceptionForName(string name)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Name = name;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentNullException>(async () =>
|
||||||
|
{
|
||||||
|
await client.UpdateTSIG(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task ShouldThrowArgumentOutOfRangeExceptionForAlgorithm()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Algorithm = 0;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentOutOfRangeException>(async () =>
|
||||||
|
{
|
||||||
|
await client.UpdateTSIG(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(null)]
|
||||||
|
[DataRow("")]
|
||||||
|
[DataRow(" ")]
|
||||||
|
public async Task ShouldThrowArgumentNullExceptionForSecret(string secret)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_request.Secret = secret;
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsExactlyAsync<ArgumentNullException>(async () =>
|
||||||
|
{
|
||||||
|
await client.UpdateTSIG(_request, TestContext.CancellationToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICloudflareClient GetClient()
|
||||||
|
{
|
||||||
|
_clientMock = new Mock<ICloudflareClient>();
|
||||||
|
_clientMock
|
||||||
|
.Setup(m => m.PutAsync<TSIG, InternalTSIGRequest>(It.IsAny<string>(), It.IsAny<InternalTSIGRequest>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Callback<string, InternalTSIGRequest, CancellationToken>((requestPath, request, _) => _callbacks.Add((requestPath, request)))
|
||||||
|
.ReturnsAsync(() => _response);
|
||||||
|
|
||||||
|
return _clientMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user