Skip to content

Commit

Permalink
add gov communication tests
Browse files Browse the repository at this point in the history
  • Loading branch information
DmyMi committed Nov 18, 2024
1 parent 301156c commit 8b1195f
Show file tree
Hide file tree
Showing 10 changed files with 285 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace OutOfSchool.AuthCommon.Config;

public class EUSignServicePaths
{
public string Certificate { get; set; }

public string Decrypt { get; set; }
}
2 changes: 2 additions & 0 deletions OutOfSchool/OutOfSchool.AuthCommon/Config/ExternalLogin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ public class ExternalLogin
public Parameters Parameters { get; set; }

public IdServerPaths IdServerPaths { get; set; }

public EUSignServicePaths EUSignServicePaths { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using OutOfSchool.AuthCommon.Config;
using OutOfSchool.AuthCommon.Models;
using OutOfSchool.AuthCommon.Services.Interfaces;
using OutOfSchool.AuthorizationServer.Services;
using OutOfSchool.Common.Config;
using OutOfSchool.Tests.Common;
using static OutOfSchool.Tests.Common.HttpClientTestHelper;

namespace OutOfSchool.AuthServer.Tests.Services;

[TestFixture]
public class GovCommunicationServiceTests
{
private Mock<IOptions<CommunicationConfig>> communicationOptions;
private Mock<IOptions<AuthorizationServerConfig>> authServerOptions;
private Mock<IHttpClientFactory> httpClientFactory;
private Mock<ILogger<GovIdentityCommunicationService>> logger;
private Mock<HttpMessageHandler> handler;
private HttpClient client;
private readonly Uri eUSignServiceUri = new("https://sign.com");
private readonly Uri idServerUri = new("https://id.com");
private IGovIdentityCommunicationService communicationService;

[SetUp]
public void SetUp()
{
handler = new Mock<HttpMessageHandler>();
client = new HttpClient(handler.Object);
var communicationConfig = new CommunicationConfig
{
ClientName = "test",
MaxNumberOfRetries = 1,
TimeoutInSeconds = 1,
};
var authServerConfig = new AuthorizationServerConfig
{
ExternalLogin = new ExternalLogin
{
EUSignServiceUri = eUSignServiceUri,
IdServerUri = idServerUri,
IdServerPaths = new IdServerPaths
{
UserInfo = "/userinfo"
},
EUSignServicePaths = new EUSignServicePaths
{
Certificate = "api/v1/certificate",
Decrypt = "api/v1/decrypt",
},
Parameters = new Parameters
{
Fields = new Fields
{
Key = "key",
Value = "value",
}
}
},
};
communicationOptions = new Mock<IOptions<CommunicationConfig>>();
communicationOptions.Setup(x => x.Value).Returns(communicationConfig);
authServerOptions = new Mock<IOptions<AuthorizationServerConfig>>();
authServerOptions.Setup(x => x.Value).Returns(authServerConfig);
httpClientFactory = new Mock<IHttpClientFactory>();
httpClientFactory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(client);
logger = new Mock<ILogger<GovIdentityCommunicationService>>();
communicationService =
new GovIdentityCommunicationService(httpClientFactory.Object, communicationOptions.Object, logger.Object,
authServerOptions.Object);
}

[Test]
public async Task GetUserInfo_WithCorrectRequest_ReturnsOkResponse()
{
// Arrange
var remoteUserId = "123";
var remoteToken = "secret";
var expectedEmail = "test@example.com";

var expected = new UserInfoResponse
{
Email = expectedEmail,
};

var certResponse = new CertificateResponse
{
CertBase64 = "cert",
};
var certSetup = SetupSendAsync(handler, HttpMethod.Get,
new Uri(eUSignServiceUri, "api/v1/certificate").ToString());
ReturnsHttpResponseAsync(certSetup, certResponse, HttpStatusCode.OK);

var infoResponse = new EnvelopedUserInfoResponse
{
EncryptedUserInfo = "serialized_info",
};

var infoSetup = SetupSendAsync(handler, HttpMethod.Get, new Uri(idServerUri, "/userinfo").ToString(), true);
ReturnsHttpResponseAsync(infoSetup, infoResponse, HttpStatusCode.OK);

var decryptSetup =
SetupSendAsync(handler, HttpMethod.Post, new Uri(eUSignServiceUri, "api/v1/decrypt").ToString());
ReturnsHttpResponseAsync(decryptSetup, expected, HttpStatusCode.OK);

// Act
var userInfo = await communicationService.GetUserInfo(remoteUserId, remoteToken);

// Assert
userInfo.AssertRight(u => Assert.AreEqual(expectedEmail, u.Email));
}

[Test]
public async Task GetUserInfo_WithEUSignCertError_ReturnsErrorResponse()
{
// Arrange
var remoteUserId = "123";
var remoteToken = "secret";
var certSetup = SetupSendAsync(handler, HttpMethod.Get,
new Uri(eUSignServiceUri, "api/v1/certificate").ToString());
ReturnsHttpResponseAsync(certSetup, null, HttpStatusCode.InternalServerError);

// Act
var userInfo = await communicationService.GetUserInfo(remoteUserId, remoteToken);

// Assert
userInfo.AssertLeft(e =>
{
Assert.IsInstanceOf<ExternalAuthError>(e);

var error = (ExternalAuthError) e;
Assert.AreEqual(ExternalAuthErrorGroup.Encryption, error.ErrorGroup);
});
}

[Test]
public async Task GetUserInfo_WithGovError_ReturnsErrorResponse()
{
// Arrange
var remoteUserId = "123";
var remoteToken = "secret";
var certResponse = new CertificateResponse
{
CertBase64 = "cert",
};
var certSetup = SetupSendAsync(handler, HttpMethod.Get,
new Uri(eUSignServiceUri, "api/v1/certificate").ToString());
ReturnsHttpResponseAsync(certSetup, certResponse, HttpStatusCode.OK);

var errorResponse = new IdGovErrorResponse
{
Error = 1,
};

var infoSetup = SetupSendAsync(handler, HttpMethod.Get, new Uri(idServerUri, "/userinfo").ToString(), true);
ReturnsHttpResponseAsync(infoSetup, errorResponse, HttpStatusCode.Unauthorized);

// Act
var userInfo = await communicationService.GetUserInfo(remoteUserId, remoteToken);

// Assert
userInfo.AssertLeft(e =>
{
Assert.IsInstanceOf<ExternalAuthError>(e);

var error = (ExternalAuthError) e;
Assert.AreEqual(ExternalAuthErrorGroup.IdGovUa, error.ErrorGroup);
Assert.AreEqual(error.HttpStatusCode, HttpStatusCode.Unauthorized);
Assert.AreEqual(error.Message, "1");
});
}

[Test]
public async Task GetUserInfo_WithEUSignDecryptError_ReturnsErrorResponse()
{
// Arrange
var remoteUserId = "123";
var remoteToken = "secret";

var certResponse = new CertificateResponse
{
CertBase64 = "cert",
};
var certSetup = SetupSendAsync(handler, HttpMethod.Get,
new Uri(eUSignServiceUri, "api/v1/certificate").ToString());
ReturnsHttpResponseAsync(certSetup, certResponse, HttpStatusCode.OK);

var infoResponse = new EnvelopedUserInfoResponse
{
EncryptedUserInfo = "serialized_info",
};

var infoSetup = SetupSendAsync(handler, HttpMethod.Get, new Uri(idServerUri, "/userinfo").ToString(), true);
ReturnsHttpResponseAsync(infoSetup, infoResponse, HttpStatusCode.OK);

var decryptSetup =
SetupSendAsync(handler, HttpMethod.Post, new Uri(eUSignServiceUri, "api/v1/decrypt").ToString());
ReturnsHttpResponseAsync(decryptSetup, null, HttpStatusCode.InternalServerError);

// Act
var userInfo = await communicationService.GetUserInfo(remoteUserId, remoteToken);

// Assert
userInfo.AssertLeft(e =>
{
Assert.IsInstanceOf<ExternalAuthError>(e);

var error = (ExternalAuthError) e;
Assert.AreEqual(ExternalAuthErrorGroup.Encryption, error.ErrorGroup);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ private Request CreateCertRequest()
return new Request
{
HttpMethodType = HttpMethodType.Get,
Url = new Uri(authServerConfig.ExternalLogin.EUSignServiceUri, "api/v1/certificate"),
Url = new Uri(
authServerConfig.ExternalLogin.EUSignServiceUri,
authServerConfig.ExternalLogin.EUSignServicePaths.Certificate),
};
}

Expand All @@ -50,7 +52,9 @@ private Request CreateDecryptionRequest(EnvelopedUserInfoResponse encryptedUser)
return new Request
{
HttpMethodType = HttpMethodType.Post,
Url = new Uri(authServerConfig.ExternalLogin.EUSignServiceUri, "api/v1/decrypt"),
Url = new Uri(
authServerConfig.ExternalLogin.EUSignServiceUri,
authServerConfig.ExternalLogin.EUSignServicePaths.Decrypt),
Data = encryptedUser,
};
}
Expand Down
4 changes: 4 additions & 0 deletions OutOfSchool/OutOfSchool.AuthorizationServer/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@
"UserInfo": "get-user-info"
},
"EUSignServiceUri": "http://localhost:8082",
"EUSignServicePaths": {
"Certificate": "api/v1/certificate",
"Decrypt": "api/v1/decrypt"
},
"ClientId": "idgovua",
"ClientSecret": "muchsecret",
"Parameters": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,17 @@
using System;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using Moq.Language.Flow;
using Moq.Protected;
using NUnit.Framework;
using OutOfSchool.Common.Communication;
using OutOfSchool.Common.Communication.ICommunication;
using OutOfSchool.Common.Config;
using OutOfSchool.Common.Models;
using OutOfSchool.Tests.Common;
using static OutOfSchool.Tests.Common.HttpClientTestHelper;

namespace OutOfSchool.WebApi.Tests.Common;

Expand Down Expand Up @@ -164,34 +161,6 @@ public async Task SendRequest_WithHttpException_ReturnsErrorResponse()
});
}

private static ISetup<HttpMessageHandler, Task<HttpResponseMessage>> SetupSendAsync(
Mock<HttpMessageHandler> handler, HttpMethod requestMethod, string requestUrl)
{
return handler.Protected().Setup<Task<HttpResponseMessage>>("SendAsync",
ItExpr.Is<HttpRequestMessage>(r =>
r.Method == requestMethod &&
r.RequestUri != null &&
r.RequestUri.ToString() == requestUrl),
ItExpr.IsAny<CancellationToken>());
}

private static IReturnsResult<HttpMessageHandler> ReturnsHttpResponseAsync(
ISetup<HttpMessageHandler, Task<HttpResponseMessage>> moqSetup,
object? responseBody,
HttpStatusCode responseCode)
{
var serializedResponse = JsonSerializer.Serialize(responseBody);
var stringContent = new StringContent(serializedResponse ?? string.Empty);

var responseMessage = new HttpResponseMessage
{
StatusCode = responseCode,
Content = stringContent,
};

return moqSetup.ReturnsAsync(responseMessage);
}

private record TestRequestData(string? Content);

private record TestResponse(string? Content) : IResponse;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" />
<PackageReference Include="MockQueryable.Moq" />
<PackageReference Include="Moq" />
<PackageReference Include="NUnit" />
<PackageReference Include="NUnit3TestAdapter" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
Expand Down
44 changes: 44 additions & 0 deletions OutOfSchool/Tests/OutOfSchool.Tests.Common/HttpClientTestHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#nullable enable

using System;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using Moq.Language.Flow;
using Moq.Protected;

namespace OutOfSchool.Tests.Common;

public static class HttpClientTestHelper
{
public static ISetup<HttpMessageHandler, Task<HttpResponseMessage>> SetupSendAsync(
Mock<HttpMessageHandler> handler, HttpMethod requestMethod, string requestUrl, bool contains = false)
{
return handler.Protected().Setup<Task<HttpResponseMessage>>("SendAsync",
ItExpr.Is<HttpRequestMessage>(r =>
r.Method == requestMethod &&
r.RequestUri != null &&
contains ? r.RequestUri.ToString().Contains(requestUrl) : r.RequestUri.ToString() == requestUrl),
ItExpr.IsAny<CancellationToken>());
}

public static IReturnsResult<HttpMessageHandler> ReturnsHttpResponseAsync(
ISetup<HttpMessageHandler, Task<HttpResponseMessage>> moqSetup,
object? responseBody,
HttpStatusCode responseCode)
{
var serializedResponse = JsonSerializer.Serialize(responseBody);
var stringContent = new StringContent(serializedResponse ?? string.Empty);

var responseMessage = new HttpResponseMessage
{
StatusCode = responseCode,
Content = stringContent,
};

return moqSetup.ReturnsAsync(responseMessage);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Moq" />
<PackageReference Include="Bogus" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="NUnit" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" />
<PackageReference Include="MockQueryable.Moq" />
<PackageReference Include="Moq" />
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="StyleCop.Analyzers">
<PrivateAssets>all</PrivateAssets>
Expand Down

0 comments on commit 8b1195f

Please sign in to comment.