Skip to content

Commit

Permalink
SLVS-1840 Provide system proxy settings to SonarQubeClient (#6040)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabriela-trutan-sonarsource authored Feb 20, 2025
1 parent 402f459 commit 0ec4364
Show file tree
Hide file tree
Showing 41 changed files with 385 additions and 512 deletions.
3 changes: 1 addition & 2 deletions src/Integration/MefServices/MefSonarQubeService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,14 @@ namespace SonarLint.VisualStudio.Integration.MefServices;
[method: ImportingConstructor]
public sealed class MefSonarQubeService(IUserAgentProvider userAgentProvider, ILogger logger, IThreadHandling threadHandling)
: SonarQubeService(
new HttpClientHandler(),
userAgent: userAgentProvider.UserAgent,
logger: new LoggerAdapter(logger))
{
protected override async Task<TResponse> InvokeUncheckedRequestAsync<TRequest, TResponse>(Action<TRequest> configure, HttpClient httpClient, CancellationToken token)
{
CodeMarkers.Instance.WebClientCallStart(typeof(TRequest).Name);

var result = await threadHandling.RunOnBackgroundThread( () => base.InvokeUncheckedRequestAsync<TRequest, TResponse>(configure, httpClient, token));
var result = await threadHandling.RunOnBackgroundThread(() => base.InvokeUncheckedRequestAsync<TRequest, TResponse>(configure, httpClient, token));

CodeMarkers.Instance.WebClientCallStop(typeof(TRequest).Name);

Expand Down
71 changes: 71 additions & 0 deletions src/SonarQube.Client.Tests/IHttpClientHandlerFactoryTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* SonarLint for Visual Studio
* Copyright (C) 2016-2025 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using System.Net;
using SonarQube.Client.Logging;

namespace SonarQube.Client.Tests;

[TestClass]
public class HttpClientHandlerFactoryTests
{
private ILogger logger;
private IProxyDetector proxyDetector;
private HttpClientHandlerFactory httpClientHandlerFactory;

[TestInitialize]
public void TestInitialize()
{
logger = Substitute.For<ILogger>();
proxyDetector = Substitute.For<IProxyDetector>();
httpClientHandlerFactory = new HttpClientHandlerFactory(proxyDetector, logger);
}

[TestMethod]
public void SystemProxyConfigured_ConfiguresHttpClientHandler()
{
var baseAddress = new Uri("http://localhost");
var proxyUri = new Uri("http://proxy");
proxyDetector.GetProxyUri(baseAddress).Returns(proxyUri);

var httpClientHandler = httpClientHandlerFactory.Create(baseAddress);

httpClientHandler.Should().NotBeNull();
var webProxy = httpClientHandler.Proxy as WebProxy;
webProxy.Should().NotBeNull();
webProxy.Address.Should().Be(proxyUri);
httpClientHandler.UseProxy.Should().BeTrue();
logger.Received(1).Debug($"System proxy detected and configured: {proxyUri}");
}

[TestMethod]
public void NoSystemProxyConfigured_DoesNotConfigureHttpClientHandler()
{
var baseAddress = new Uri("http://localhost");
proxyDetector.GetProxyUri(baseAddress).Returns(baseAddress);

var httpClientHandler = httpClientHandlerFactory.Create(baseAddress);

httpClientHandler.Should().NotBeNull();
httpClientHandler.Proxy.Should().BeNull();
httpClientHandler.UseProxy.Should().BeTrue(); // default value is true
logger.Received(1).Debug("No system proxy detected");
}
}
36 changes: 16 additions & 20 deletions src/SonarQube.Client.Tests/Infra/MocksHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,9 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using Moq.Protected;

Expand All @@ -34,41 +30,41 @@ internal static class MocksHelper
{
public const string ValidBaseAddress = "http://localhost";

public const string EmptyGetIssuesResponse = @"{""total"":0,""p"":1,""ps"":10,""paging"":{""pageIndex"":1,""pageSize"":10,""total"":0},""effortTotal"":0,""debtTotal"":0,""issues"":[],""components"":[],""organizations"":[],""facets"":[]}";
public const string EmptyGetIssuesResponse
= @"{""total"":0,""p"":1,""ps"":10,""paging"":{""pageIndex"":1,""pageSize"":10,""total"":0},""effortTotal"":0,""debtTotal"":0,""issues"":[],""components"":[],""organizations"":[],""facets"":[]}";

/// <summary>
/// Sets up the HTTP message handler mock to respond to any request string
/// </summary>
public static void SetupHttpRequest(Mock<HttpMessageHandler> messageHandlerMock, string response,
public static void SetupHttpRequest(
Mock<HttpClientHandler> messageHandlerMock,
string response,
HttpStatusCode statusCode = HttpStatusCode.OK)
{
messageHandlerMock.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.Returns(Task.FromResult(new HttpResponseMessage
{
StatusCode = statusCode,
Content = new StringContent(response)
}));
.Returns(Task.FromResult(new HttpResponseMessage { StatusCode = statusCode, Content = new StringContent(response) }));
}

/// <summary>
/// Sets up the HTTP message handler mock to reply to a specific request string
/// </summary>
public static void SetupHttpRequest(Mock<HttpMessageHandler> messageHandlerMock, string requestRelativePath, string response,
HttpStatusCode statusCode = HttpStatusCode.OK, string basePath = ValidBaseAddress)
public static void SetupHttpRequest(
Mock<HttpClientHandler> messageHandlerMock,
string requestRelativePath,
string response,
HttpStatusCode statusCode = HttpStatusCode.OK,
string basePath = ValidBaseAddress)
{
var responseMessage = new HttpResponseMessage
{
StatusCode = statusCode,
Content = new StringContent(response)
};
var responseMessage = new HttpResponseMessage { StatusCode = statusCode, Content = new StringContent(response) };

SetupHttpRequest(messageHandlerMock, requestRelativePath, responseMessage, basePath);
}

public static void SetupHttpRequest(Mock<HttpMessageHandler> messageHandlerMock,
public static void SetupHttpRequest(
Mock<HttpClientHandler> messageHandlerMock,
string requestRelativePath,
HttpResponseMessage responseMessage,
string basePath = ValidBaseAddress,
Expand All @@ -88,7 +84,7 @@ public static void SetupHttpRequest(Mock<HttpMessageHandler> messageHandlerMock,
/// <summary>
/// Returns the actual requests passed to the SendAsync method
/// </summary>
public static HttpRequestMessage[] GetSendAsyncRequests(this Mock<HttpMessageHandler> handler) =>
public static HttpRequestMessage[] GetSendAsyncRequests(this Mock<HttpClientHandler> handler) =>
handler.Invocations.Where(x => x.Method.Name == "SendAsync")
.Select(x => (HttpRequestMessage)x.Arguments[0])
.ToArray();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SonarQube.Client.Api.V7_20;
using SonarQube.Client.Tests.Infra;
Expand All @@ -45,11 +40,8 @@ public async Task InvokeAsync_AllSettingAreMissing_ReturnsEmptyConfiguration(str

var testSubject = CreateTestSubject(projectKey);

var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
var httpClient = new HttpClient(handlerMock.Object)
{
BaseAddress = new Uri(ValidBaseAddress)
};
var handlerMock = new Mock<HttpClientHandler>(MockBehavior.Strict);
var httpClient = new HttpClient(handlerMock.Object) { BaseAddress = new Uri(ValidBaseAddress) };

var request = $"api/settings/values?component={projectKey}&keys=sonar.exclusions%2Csonar.global.exclusions%2Csonar.inclusions";

Expand All @@ -71,11 +63,8 @@ public async Task InvokeAsync_SomeMissingSetting_ReturnsDefinedProperties()

var testSubject = CreateTestSubject(projectKey);

var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
var httpClient = new HttpClient(handlerMock.Object)
{
BaseAddress = new Uri(ValidBaseAddress)
};
var handlerMock = new Mock<HttpClientHandler>(MockBehavior.Strict);
var httpClient = new HttpClient(handlerMock.Object) { BaseAddress = new Uri(ValidBaseAddress) };

var request = $"api/settings/values?component={projectKey}&keys=sonar.exclusions%2Csonar.global.exclusions%2Csonar.inclusions";
var response = @"{
Expand Down Expand Up @@ -106,11 +95,8 @@ public async Task InvokeAsync_ExistingSetting_ReturnsDefinedProperties()

var testSubject = CreateTestSubject(projectKey);

var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
var httpClient = new HttpClient(handlerMock.Object)
{
BaseAddress = new Uri(ValidBaseAddress)
};
var handlerMock = new Mock<HttpClientHandler>(MockBehavior.Strict);
var httpClient = new HttpClient(handlerMock.Object) { BaseAddress = new Uri(ValidBaseAddress) };

var request = $"api/settings/values?component={projectKey}&keys=sonar.exclusions%2Csonar.global.exclusions%2Csonar.inclusions";
var response = @"{
Expand Down Expand Up @@ -148,14 +134,9 @@ public async Task InvokeAsync_ExistingSetting_ReturnsDefinedProperties()
result.Inclusions.Should().BeEquivalentTo("**/111");
}


private static GetExclusionsRequest CreateTestSubject(string projectKey)
{
var testSubject = new GetExclusionsRequest
{
Logger = new TestLogger(),
ProjectKey = projectKey
};
var testSubject = new GetExclusionsRequest { Logger = new TestLogger(), ProjectKey = projectKey };

return testSubject;
}
Expand Down
Loading

0 comments on commit 0ec4364

Please sign in to comment.