-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #44 from FromDoppler/DD-1292-dkims-sdk-integration
SDK DKIMs integration
- Loading branch information
Showing
8 changed files
with
385 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
using GreenArrow.Engine.DKIMKeysApi; | ||
using GreenArrow.Engine.Extensions; | ||
using GreenArrow.Engine.HttpSubmissionApi; | ||
using GreenArrow.Engine.RestApi; | ||
using Microsoft.Extensions.Options; | ||
using Moq.Protected; | ||
using System.Net; | ||
|
||
namespace GreenArrow.Engine.Test.HttpSubmissionApi | ||
{ | ||
public class DKIMKeysApiTest | ||
{ | ||
private static readonly Fixture specimens = new(); | ||
|
||
private static IDKIMKeysApi CreateSut( | ||
GreenArrowEngineSettings? settings = null, | ||
IHttpClientFactory? httpClientFactory = null | ||
) | ||
{ | ||
settings ??= new GreenArrowEngineSettings { ServerUri = $"https://localhost/" }; | ||
|
||
return new DKIMKeysApiClient( | ||
options: Options.Create(settings), | ||
httpFactory: httpClientFactory ?? Mock.Of<IHttpClientFactory>() | ||
); | ||
} | ||
|
||
private static Mock<HttpMessageHandler> CreateHttpMessageHandlerMock(HttpResponseMessage httpResponseMessage) | ||
{ | ||
var httpMessageHandlerMock = new Mock<HttpMessageHandler>(); | ||
httpMessageHandlerMock.Protected() | ||
.Setup<Task<HttpResponseMessage>>(nameof(HttpClient.SendAsync), ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>()) | ||
.ReturnsAsync(httpResponseMessage); | ||
|
||
return httpMessageHandlerMock; | ||
} | ||
|
||
private static Mock<HttpMessageHandler> CreateHttpMessageHandlerMock(Exception exception) | ||
{ | ||
var httpMessageHandlerMock = new Mock<HttpMessageHandler>(); | ||
httpMessageHandlerMock.Protected() | ||
.Setup<Task<HttpResponseMessage>>(nameof(HttpClient.SendAsync), ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>()) | ||
.ThrowsAsync(exception); | ||
|
||
return httpMessageHandlerMock; | ||
} | ||
|
||
private static Mock<IHttpClientFactory> CreateHttpClientFactoryMock(HttpMessageHandler httpMessageHandler) | ||
{ | ||
var httpClient = new HttpClient(httpMessageHandler); | ||
|
||
var httpClientFactoryMock = new Mock<IHttpClientFactory>(); | ||
httpClientFactoryMock | ||
.Setup(_ => _.CreateClient(It.IsAny<string>())) | ||
.Returns(httpClient); | ||
|
||
return httpClientFactoryMock; | ||
} | ||
|
||
[Fact] | ||
public async Task Should_request_to_the_configured_endpoint_name() | ||
{ | ||
// Arrange | ||
var settings = new GreenArrowEngineSettings { ServerUri = $"https://localhost/", DKIMKeysAPIEndpoint = "/api/v3/eng/dkim_keys" }; | ||
var httpResponseMessage = new HttpResponseMessage | ||
{ | ||
StatusCode = specimens.Create<HttpStatusCode>(), | ||
}; | ||
|
||
var httpMessageHandlerMock = CreateHttpMessageHandlerMock(httpResponseMessage); | ||
var httpClientFactoryMock = CreateHttpClientFactoryMock(httpMessageHandlerMock.Object); | ||
var sut = CreateSut(settings, httpClientFactory: httpClientFactoryMock.Object); | ||
|
||
var request = specimens.Create<DKIMKeysRequest>(); | ||
|
||
// Act | ||
await sut.PostAsync(request, CancellationToken.None); | ||
|
||
// Assert | ||
httpMessageHandlerMock.Protected().Verify( | ||
nameof(HttpClient.SendAsync), | ||
Times.Exactly(1), | ||
ItExpr.Is<HttpRequestMessage>(request => request.RequestUri.AbsolutePath.EndsWith(settings.DKIMKeysAPIEndpoint)), | ||
ItExpr.IsAny<CancellationToken>() | ||
); | ||
} | ||
|
||
[Fact] | ||
public async Task Post_should_return_http_status_code_on_sucessfull() | ||
{ | ||
// Arrange | ||
var httpResponseMessage = new HttpResponseMessage | ||
{ | ||
StatusCode = specimens.Create<HttpStatusCode>(), | ||
}; | ||
|
||
var httpMessageHandlerMock = CreateHttpMessageHandlerMock(httpResponseMessage); | ||
var httpClientFactoryMock = CreateHttpClientFactoryMock(httpMessageHandlerMock.Object); | ||
var sut = CreateSut(httpClientFactory: httpClientFactoryMock.Object); | ||
|
||
var request = specimens.Create<DKIMKeysRequest>(); | ||
|
||
// Act | ||
var result = await sut.PostAsync(request, CancellationToken.None); | ||
|
||
// Assert | ||
Assert.Equal(httpResponseMessage.StatusCode, result.HttpStatusCode); | ||
} | ||
|
||
[Fact] | ||
public async Task Post_should_throw_RestApiException_upon_an_exception_in_the_implementation() | ||
{ | ||
// Arrange | ||
var exception = specimens.Create<Exception>(); | ||
|
||
var httpMessageHandlerMock = CreateHttpMessageHandlerMock(exception); | ||
var httpClientFactoryMock = CreateHttpClientFactoryMock(httpMessageHandlerMock.Object); | ||
var sut = CreateSut(httpClientFactory: httpClientFactoryMock.Object); | ||
|
||
var request = specimens.Create<DKIMKeysRequest>(); | ||
var cancellationToken = specimens.Create<CancellationToken>(); | ||
|
||
// Act | ||
var result = await Assert.ThrowsAsync<RestApiException>(() => sut.PostAsync(request, cancellationToken)); | ||
|
||
// Assert | ||
Assert.Equal(exception, result.InnerException); | ||
} | ||
|
||
[Fact] | ||
public async Task Post_should_return_deserialized_response_content_on_sucessfull() | ||
{ | ||
// Arrange | ||
var DKIMKeysResponse = specimens.Create<DKIMKeysResponse>(); | ||
var httpContent = new StringContent(DKIMKeysResponse.ToJson(true)); | ||
|
||
var httpResponseMessage = new HttpResponseMessage | ||
{ | ||
StatusCode = HttpStatusCode.OK, | ||
Content = httpContent, | ||
}; | ||
|
||
var httpMessageHandlerMock = CreateHttpMessageHandlerMock(httpResponseMessage); | ||
var httpClientFactoryMock = CreateHttpClientFactoryMock(httpMessageHandlerMock.Object); | ||
var sut = CreateSut(httpClientFactory: httpClientFactoryMock.Object); | ||
|
||
var request = specimens.Create<DKIMKeysRequest>(); | ||
|
||
// Act | ||
var result = await sut.PostAsync(request, CancellationToken.None); | ||
|
||
// Assert | ||
Assert.Equal(DKIMKeysResponse.Success, result.Content.Success); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
using GreenArrow.Engine.Extensions; | ||
using GreenArrow.Engine.RestApi; | ||
using Microsoft.Extensions.Options; | ||
using System.Net; | ||
using System.Net.Http.Headers; | ||
|
||
namespace GreenArrow.Engine.DKIMKeysApi | ||
{ | ||
/// <summary> | ||
/// DKIM Keys API client implementation | ||
/// </summary> | ||
public class DKIMKeysApiClient : IDKIMKeysApi | ||
{ | ||
private readonly GreenArrowEngineSettings _settings; | ||
private readonly IHttpClientFactory _httpFactory; | ||
|
||
private readonly string _endpoint; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of Green Arrow DKIM Keys API Client | ||
/// </summary> | ||
/// <param name="options">Green Arrow settings with API Url and Authorization Token</param> | ||
/// <param name="httpFactory">HttpClienFactory for create HttpClient objects</param> | ||
public DKIMKeysApiClient( | ||
IOptions<GreenArrowEngineSettings> options, | ||
IHttpClientFactory httpFactory) | ||
{ | ||
_settings = options.Value; | ||
_httpFactory = httpFactory; | ||
_endpoint = GetEndPoint(); | ||
} | ||
|
||
private HttpClient CreateHttpClient() | ||
{ | ||
var client = _httpFactory.CreateClient(); | ||
return client; | ||
} | ||
|
||
private string GetEndPoint() | ||
{ | ||
var baseUri = new Uri(_settings.ServerUri); | ||
var endpointUri = new Uri(baseUri, _settings.DKIMKeysAPIEndpoint); | ||
return endpointUri.ToString(); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public async Task<IRestApiResponse<DKIMKeysResponse>> PostAsync(DKIMKeysRequest request, CancellationToken cancellationToken = default) | ||
{ | ||
try | ||
{ | ||
var jsonContent = request.ToJson(); | ||
|
||
var client = CreateHttpClient(); | ||
|
||
var authenticationString = $"{request.Username}:{request.Password}"; | ||
var base64EncodedAuthenticationString = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(authenticationString)); | ||
|
||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64EncodedAuthenticationString); | ||
|
||
var httpContent = new StringContent(jsonContent, encoding: default, mediaType: "application/json"); | ||
var httpResponse = await client.PostAsync(_endpoint, httpContent, cancellationToken); | ||
|
||
if (httpResponse.StatusCode == HttpStatusCode.OK) | ||
{ | ||
var result = await httpResponse.Content.ReadAsStringAsync(cancellationToken); | ||
var content = result.ToObject<DKIMKeysResponse>(); | ||
return new RestApiResponse<DKIMKeysResponse>(httpResponse.StatusCode, content); | ||
} | ||
|
||
return new RestApiResponse<DKIMKeysResponse>(httpResponse.StatusCode); | ||
|
||
} | ||
catch (Exception exception) | ||
{ | ||
throw new RestApiException("Unexpected exception", exception); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
using GreenArrow.Engine.Model; | ||
using GreenArrow.Engine.RestApi; | ||
using Newtonsoft.Json; | ||
using Newtonsoft.Json.Serialization; | ||
|
||
namespace GreenArrow.Engine.DKIMKeysApi | ||
{ | ||
/// <summary> | ||
/// Create a DKIM Key Request | ||
/// </summary> | ||
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy), ItemNullValueHandling = NullValueHandling.Ignore)] | ||
public class DKIMKeysRequest : IRestApiModel | ||
{ | ||
/// <summary> | ||
/// Username that is authorized to log in to GreenArrow Engine’s web interface. | ||
/// </summary> | ||
public string Username { get; set; } | ||
|
||
/// <summary> | ||
/// Password that is authorized to log in to GreenArrow Engine’s web interface. | ||
/// </summary> | ||
public string Password { get; set; } | ||
|
||
/// <summary> | ||
/// To create the private key | ||
/// </summary> | ||
public DkimKey DkimKey { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
using GreenArrow.Engine.Model; | ||
using GreenArrow.Engine.RestApi; | ||
|
||
namespace GreenArrow.Engine.DKIMKeysApi | ||
{ | ||
/// <summary> | ||
/// GreenArrow Response is the full DKIM Key record data | ||
/// </summary> | ||
public class DKIMKeysResponse : IRestApiModel | ||
{ | ||
/// <summary> | ||
/// When request was succesful created | ||
/// </summary> | ||
public bool Success { get; init; } | ||
|
||
/// <summary> | ||
/// Full DKIM Key record data | ||
/// </summary> | ||
public DKIMKeysResponseData Data { get; init; } | ||
|
||
/// <summary> | ||
/// Error code when request was not accepted | ||
/// </summary> | ||
public string ErrorCode { get; init; } | ||
|
||
/// <summary> | ||
/// Error message when request was not accepted | ||
/// </summary> | ||
public string ErrorMessages { get; init; } | ||
} | ||
|
||
/// <summary> | ||
/// Full DKIM Key record data | ||
/// </summary> | ||
public class DKIMKeysResponseData | ||
{ | ||
/// <summary> | ||
/// Full DKIM Key record data | ||
/// </summary> | ||
public DkimKey DkimKey { get; init; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using GreenArrow.Engine.RestApi; | ||
|
||
namespace GreenArrow.Engine.DKIMKeysApi | ||
{ | ||
/// <summary> | ||
/// Represent the actions available in Green Arrow Engine DKIM Keys API | ||
/// </summary> | ||
/// <remarks><see href="https://www.greenarrowemail.com/docs/greenarrow-engine/API-V3/Engine/DKIM-Keys"/></remarks> | ||
public interface IDKIMKeysApi | ||
{ | ||
/// <summary> | ||
/// Create a DKIM Key | ||
/// </summary> | ||
/// <param name="request"></param> | ||
/// <param name="cancellationToken">The cancellation token</param> | ||
/// <returns>A generic rest api response with the deserialized DKIM Keys API response when success</returns> | ||
Task<IRestApiResponse<DKIMKeysResponse>> PostAsync(DKIMKeysRequest request, CancellationToken cancellationToken = default); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.