diff --git a/backend/src/Designer/TypedHttpClients/DelegatingHandlers/AzureDevOpsTokenDelegatingHandler.cs b/backend/src/Designer/TypedHttpClients/DelegatingHandlers/AzureDevOpsTokenDelegatingHandler.cs new file mode 100644 index 00000000000..6832d5d11a6 --- /dev/null +++ b/backend/src/Designer/TypedHttpClients/DelegatingHandlers/AzureDevOpsTokenDelegatingHandler.cs @@ -0,0 +1,24 @@ +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace Altinn.Studio.Designer.TypedHttpClients.DelegatingHandlers; + +public class AzureDevOpsTokenDelegatingHandler : DelegatingHandler +{ + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + HttpResponseMessage response = await base.SendAsync(request, cancellationToken); + + if (response.StatusCode == HttpStatusCode.Unauthorized) + { + return new HttpResponseMessage(HttpStatusCode.InternalServerError) + { + Content = new StringContent("Failed to interact with Azure DevOps. Contact system support.") + }; + } + + return response; + } +} diff --git a/backend/src/Designer/TypedHttpClients/TypedHttpClientRegistration.cs b/backend/src/Designer/TypedHttpClients/TypedHttpClientRegistration.cs index 7b387507409..b20fe66cad4 100644 --- a/backend/src/Designer/TypedHttpClients/TypedHttpClientRegistration.cs +++ b/backend/src/Designer/TypedHttpClients/TypedHttpClientRegistration.cs @@ -38,6 +38,7 @@ public static class TypedHttpClientRegistration public static IServiceCollection RegisterTypedHttpClients(this IServiceCollection services, IConfiguration config) { services.AddHttpClient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddAzureDevOpsTypedHttpClient(config); @@ -70,7 +71,7 @@ private static IHttpClientBuilder AddAzureDevOpsTypedHttpClient(this IServiceCol client.BaseAddress = new Uri($"{azureDevOpsSettings.BaseUri}build/builds/"); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", token); - }).AddHttpMessageHandler(); + }).AddHttpMessageHandler().AddHttpMessageHandler(); } private static IHttpClientBuilder AddKubernetesWrapperTypedHttpClient(this IServiceCollection services) diff --git a/backend/tests/Designer.Tests/TypedHttpClients/DelegatingHandlers/AzureDevOpsTokenDelegatingHandlerTests.cs b/backend/tests/Designer.Tests/TypedHttpClients/DelegatingHandlers/AzureDevOpsTokenDelegatingHandlerTests.cs new file mode 100644 index 00000000000..ee54efa5b68 --- /dev/null +++ b/backend/tests/Designer.Tests/TypedHttpClients/DelegatingHandlers/AzureDevOpsTokenDelegatingHandlerTests.cs @@ -0,0 +1,70 @@ +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Altinn.Studio.Designer.TypedHttpClients.DelegatingHandlers; +using Moq; +using Moq.Protected; +using Xunit; + +public class AzureDevOpsTokenDelegatingHandlerTests +{ + [Fact] + public async Task SendAsync_WhenUnauthorized_ThrowsHttpRequestException() + { + // Arrange + var mockInnerHandler = new Mock(); + + mockInnerHandler.Protected() + .Setup>("SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage + { + StatusCode = HttpStatusCode.Unauthorized + }); + + var handler = new AzureDevOpsTokenDelegatingHandler + { + InnerHandler = mockInnerHandler.Object + }; + + HttpClient httpClient = new HttpClient(handler); + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://dev.azure.com"); + + HttpResponseMessage response = await httpClient.SendAsync(request); + string content = await response.Content.ReadAsStringAsync(); + + Assert.Equal("Failed to interact with Azure DevOps. Contact system support.", content); + Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); + } + + [Fact] + public async Task SendAsync_WhenSuccessful_ReturnsResponse() + { + var mockInnerHandler = new Mock(); + + mockInnerHandler.Protected() + .Setup>("SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent("Success") + }); + + var handler = new AzureDevOpsTokenDelegatingHandler + { + InnerHandler = mockInnerHandler.Object + }; + + HttpClient httpClient = new HttpClient(handler); + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://dev.azure.com"); + + HttpResponseMessage response = await httpClient.SendAsync(request); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("Success", await response.Content.ReadAsStringAsync()); + } +}