Skip to content

Commit

Permalink
SLVS-1407 Integrate BoundServerProject with IBindingProcess (#5655)
Browse files Browse the repository at this point in the history
[SLVS-1407](https://sonarsource.atlassian.net/browse/SLVS-1407)

Part of <!-- 
  Only for standalone PRs without Jira issue in the PR title: 
    * Replace this comment with Epic ID to create a new Task in Jira
* Replace this comment with Issue ID to create a new Sub-Task in Jira
* Ignore or delete this note to create a new Task in Jira without a
parent
-->


[SLVS-1407]:
https://sonarsource.atlassian.net/browse/SLVS-1407?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
  • Loading branch information
georgii-borovinskikh-sonarsource authored and vnaskos-sonar committed Sep 19, 2024
1 parent 0fc33ac commit 4af1c03
Show file tree
Hide file tree
Showing 37 changed files with 986 additions and 841 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
using SonarLint.VisualStudio.ConnectedMode.QualityProfiles;
using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Core.Analysis;
using SonarLint.VisualStudio.Core.Binding;
using SonarLint.VisualStudio.TestInfrastructure;
using SonarQube.Client;
using SonarQube.Client.Models;
Expand All @@ -45,7 +46,7 @@ public void MefCtor_CheckIsExported()
[TestMethod]
public void Create_ReturnsProcessImpl()
{
var bindingArgs = new BindCommandArgs("proj key", "proj name", new ConnectionInformation(new Uri("http://localhost")));
var bindingArgs = new BindCommandArgs(new BoundServerProject("any", "any", new ServerConnection.SonarCloud("any")));

var testSubject = CreateTestSubject();

Expand Down
69 changes: 10 additions & 59 deletions src/ConnectedMode.UnitTests/Binding/BindingProcessImplTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class BindingProcessImplTests
[TestMethod]
public void Ctor_ArgChecks()
{
var bindingArgs = CreateBindCommandArgs(connection: new ConnectionInformation(new Uri("http://server")));
var bindingArgs = CreateBindCommandArgs();
var exclusionSettingsStorage = Mock.Of<IExclusionSettingsStorage>();
var qpDownloader = Mock.Of<IQualityProfileDownloader>();
var sonarQubeService = Mock.Of<ISonarQubeService>();
Expand Down Expand Up @@ -150,9 +150,7 @@ public async Task DownloadQualityProfile_CreatesBoundProjectAndCallsQPDownloader
var qpDownloader = new Mock<IQualityProfileDownloader>();
var progress = Mock.Of<IProgress<FixedStepsProgress>>();

var connectionInfo = new ConnectionInformation(new Uri("http://theServer"));
connectionInfo.Organization = new SonarQubeOrganization("the org key", "the org name");
var bindingArgs = CreateBindCommandArgs("the project key", "the project name", connectionInfo);
var bindingArgs = CreateBindCommandArgs("the project key", "http://theServer");

var testSubject = CreateTestSubject(bindingArgs,
qpDownloader: qpDownloader.Object);
Expand All @@ -162,61 +160,15 @@ public async Task DownloadQualityProfile_CreatesBoundProjectAndCallsQPDownloader

result.Should().BeTrue();

qpDownloader.Verify(x => x.UpdateAsync(It.IsAny<BoundSonarQubeProject>(), progress, It.IsAny<CancellationToken>()),
qpDownloader.Verify(x => x.UpdateAsync(It.IsAny<BoundServerProject>(), progress, It.IsAny<CancellationToken>()),
Times.Once);

var actualProject = (BoundSonarQubeProject)qpDownloader.Invocations[0].Arguments[0];
var actualProject = (BoundServerProject)qpDownloader.Invocations[0].Arguments[0];

// Check the bound project was correctly constructed from the BindCommandArgs
actualProject.Should().NotBeNull();
actualProject.ServerUri.Should().Be("http://theServer");
actualProject.ProjectKey.Should().Be("the project key");
actualProject.ProjectName.Should().Be("the project name");
actualProject.Organization.Key.Should().Be("the org key");
actualProject.Organization.Name.Should().Be("the org name");
}

[TestMethod]
[DataRow("the user name", null)]
[DataRow("the user name", "a password")]
[DataRow(null, null)]
[DataRow(null, "should be ignored")]
public async Task DownloadQualityProfile_HandlesBoundProjectCredentialsCorrectly(string userName, string rawPassword)
{
var qpDownloader = new Mock<IQualityProfileDownloader>();
var password = rawPassword == null ? null : rawPassword.ToSecureString();

var connectionInfo = new ConnectionInformation(new Uri("http://any"), userName, password);
var bindingArgs = CreateBindCommandArgs(connection: connectionInfo);

var testSubject = CreateTestSubject(bindingArgs,
qpDownloader: qpDownloader.Object);

// Act
var result = await testSubject.DownloadQualityProfileAsync(Mock.Of<IProgress<FixedStepsProgress>>(), CancellationToken.None);

result.Should().BeTrue();

qpDownloader.Verify(x => x.UpdateAsync(It.IsAny<BoundSonarQubeProject>(),
It.IsAny<IProgress<FixedStepsProgress>>(),
It.IsAny<CancellationToken>()),
Times.Once);

var actualProject = (BoundSonarQubeProject)qpDownloader.Invocations[0].Arguments[0];

// Check the credentials were handled correctly
if (userName == null)
{
actualProject.Credentials.Should().BeNull();
}
else
{
actualProject.Credentials.Should().BeOfType<BasicAuthCredentials>();
var actualCreds = (BasicAuthCredentials)actualProject.Credentials;

actualCreds.UserName.Should().Be(userName);
CheckIsExpectedPassword(rawPassword, actualCreds.Password);
}
actualProject.ServerConnection.ServerUri.Should().Be("http://theServer");
actualProject.ServerProjectKey.Should().Be("the project key");
}

[TestMethod]
Expand All @@ -225,7 +177,7 @@ public async Task DownloadQualityProfile_HandlesInvalidOperationException()
var qpDownloader = new Mock<IQualityProfileDownloader>();
qpDownloader
.Setup(x =>
x.UpdateAsync(It.IsAny<BoundSonarQubeProject>(),
x.UpdateAsync(It.IsAny<BoundServerProject>(),
It.IsAny<IProgress<FixedStepsProgress>>(),
It.IsAny<CancellationToken>()))
.Throws(new InvalidOperationException());
Expand All @@ -238,7 +190,7 @@ public async Task DownloadQualityProfile_HandlesInvalidOperationException()
await testSubject.DownloadQualityProfileAsync(Mock.Of<IProgress<FixedStepsProgress>>(), CancellationToken.None);

result.Should().BeFalse();
qpDownloader.Verify(x => x.UpdateAsync(It.IsAny<BoundSonarQubeProject>(),
qpDownloader.Verify(x => x.UpdateAsync(It.IsAny<BoundServerProject>(),
It.IsAny<IProgress<FixedStepsProgress>>(),
It.IsAny<CancellationToken>()),
Times.Once);
Expand Down Expand Up @@ -267,10 +219,9 @@ private BindingProcessImpl CreateTestSubject(BindCommandArgs bindingArgs = null,
logger);
}

private BindCommandArgs CreateBindCommandArgs(string projectKey = "key", string projectName = "name", ConnectionInformation connection = null)
private BindCommandArgs CreateBindCommandArgs(string projectKey = "key", string serverUri = "http://any")
{
connection = connection ?? new ConnectionInformation(new Uri("http://connected"));
return new BindCommandArgs(projectKey, projectName, connection);
return new BindCommandArgs(new BoundServerProject("any", projectKey, new ServerConnection.SonarQube(new Uri(serverUri))));
}

private static void CheckIsExpectedPassword(string expectedRawPassword, SecureString actualPassword)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public void GetRules_UnsupportedLanguage_Throws()
var testSubject = builder.CreateTestSubject();

// Act
Action act = () => testSubject.GetConfigurationAsync(validQualityProfile, Language.Cpp, LegacyBindingConfiguration.Standalone, CancellationToken.None).Wait();
Action act = () => testSubject.GetConfigurationAsync(validQualityProfile, Language.Cpp, BindingConfiguration.Standalone, CancellationToken.None).Wait();

// Assert
act.Should().ThrowExactly<ArgumentOutOfRangeException>().And.ParamName.Should().Be("language");
Expand Down Expand Up @@ -185,7 +185,6 @@ public async Task GetConfig_ReturnsCorrectAdditionalFile()
public async Task GetConfig_HasActiveInactiveAndUnsupportedRules_ReturnsValidBindingConfig()
{
// Arrange
const string expectedProjectName = "my project";
const string expectedServerUrl = "http://myhost:123/";

var properties = new SonarQubeProperty[]
Expand All @@ -207,7 +206,7 @@ public async Task GetConfig_HasActiveInactiveAndUnsupportedRules_ReturnsValidBin
InactiveRuleWithUnsupportedSeverity
};

var builder = new TestEnvironmentBuilder(validQualityProfile, Language.CSharp, expectedProjectName, expectedServerUrl)
var builder = new TestEnvironmentBuilder(validQualityProfile, Language.CSharp, expectedServerUrl)
{
ActiveRulesResponse = activeRules,
InactiveRulesResponse = inactiveRules,
Expand Down Expand Up @@ -278,25 +277,22 @@ private class TestEnvironmentBuilder

private readonly SonarQubeQualityProfile profile;
private readonly Language language;
private readonly string projectName;
private readonly string serverUrl;

private const string ExpectedProjectKey = "fixed.project.key";

public TestEnvironmentBuilder(SonarQubeQualityProfile profile, Language language,
string projectName = "any", string serverUrl = "http://any")
public TestEnvironmentBuilder(SonarQubeQualityProfile profile, Language language, string serverUrl = "http://any")
{
this.profile = profile;
this.language = language;
this.projectName = projectName;
this.serverUrl = serverUrl;

Logger = new TestLogger();
SonarLintConfigurationResponse = new SonarLintConfiguration();
PropertiesResponse = new List<SonarQubeProperty>();
}

public LegacyBindingConfiguration BindingConfiguration { get; private set; }
public BindingConfiguration BindingConfiguration { get; private set; }
public SonarLintConfiguration SonarLintConfigurationResponse { get; set; }
public IList<SonarQubeRule> ActiveRulesResponse { get; set; }
public IList<SonarQubeRule> InactiveRulesResponse { get; set; }
Expand Down Expand Up @@ -342,8 +338,10 @@ public CSharpVBBindingConfigProvider CreateTestSubject()
CapturedRulesPassedToGlobalConfigGenerator = rules;
});

BindingConfiguration = new LegacyBindingConfiguration(new BoundSonarQubeProject(new Uri(serverUrl), ExpectedProjectKey, projectName),
SonarLintMode.Connected, "c:\\test\\");
BindingConfiguration = new BindingConfiguration(
new BoundServerProject("solution", ExpectedProjectKey, new ServerConnection.SonarQube(new Uri(serverUrl))),
SonarLintMode.Connected,
"c:\\test\\");

var sonarProperties = PropertiesResponse.ToDictionary(x => x.Key, y => y.Value);
sonarLintConfigGeneratorMock
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public async Task GetConfiguration_WithMatchingProvider_ExpectedConfigReturned()
var testSubject = new CompositeBindingConfigProvider(otherProvider, cppProvider1, cppProvider2);

// Act. Multiple matching providers -> config from the first matching provider returned
var actualConfig = await testSubject.GetConfigurationAsync(qp, Language.Cpp, LegacyBindingConfiguration.Standalone, CancellationToken.None);
var actualConfig = await testSubject.GetConfigurationAsync(qp, Language.Cpp, BindingConfiguration.Standalone, CancellationToken.None);
actualConfig.Should().Be(cppProvider1.ConfigToReturn);
}

Expand All @@ -105,7 +105,7 @@ public void GetConfiguration_NoMatchingProvider_Throws()
var testSubject = new CompositeBindingConfigProvider(otherProvider);

// 1. Multiple matching providers -> config from the first matching provider returned
Func<Task> act = async () => await testSubject.GetConfigurationAsync(qp, Language.Cpp, LegacyBindingConfiguration.Standalone, CancellationToken.None);
Func<Task> act = async () => await testSubject.GetConfigurationAsync(qp, Language.Cpp, BindingConfiguration.Standalone, CancellationToken.None);

act.Should().ThrowExactly<ArgumentOutOfRangeException>();
}
Expand All @@ -129,7 +129,8 @@ public DummyProvider(IBindingConfig configToReturn = null, params Language[] sup

#region IBindingConfigProvider implementation

public Task<IBindingConfig> GetConfigurationAsync(SonarQubeQualityProfile qualityProfile, Language language, LegacyBindingConfiguration bindingConfiguration, CancellationToken cancellationToken)
public Task<IBindingConfig> GetConfigurationAsync(SonarQubeQualityProfile qualityProfile, Language language,
BindingConfiguration bindingConfiguration, CancellationToken cancellationToken)
{
return Task.FromResult(ConfigToReturn);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public async Task GetRules_Success()
serviceMock.Setup(x => x.GetRulesAsync(true, It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(() => rules);

var bindingConfiguration = new LegacyBindingConfiguration(new BoundSonarQubeProject { ProjectKey = "test" }, SonarLintMode.Connected, "c:\\");
var bindingConfiguration = new BindingConfiguration(new BoundServerProject("any", "any", new ServerConnection.SonarCloud("any")), SonarLintMode.Connected, "c:\\");

var testSubject = CreateTestSubject(serviceMock, testLogger);

Expand Down Expand Up @@ -176,7 +176,7 @@ public async Task GetRules_NoData_EmptyResultReturned()
serviceMock.Setup(x => x.GetRulesAsync(It.IsAny<bool>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(() => new List<SonarQubeRule>());

var bindingConfiguration = new LegacyBindingConfiguration(new BoundSonarQubeProject { ProjectKey = "test" }, SonarLintMode.Connected, "c:\\");
var bindingConfiguration = new BindingConfiguration(new BoundServerProject("any", "any", new ServerConnection.SonarCloud("any")), SonarLintMode.Connected, "c:\\");

var testSubject = CreateTestSubject(serviceMock, testLogger);

Expand Down Expand Up @@ -208,7 +208,7 @@ public async Task GetRules_NonCriticalException_IsHandledAndNullResultReturned()
var testSubject = CreateTestSubject(serviceMock, testLogger);

// Act
var result = await testSubject.GetConfigurationAsync(CreateQp(), Language.Cpp, LegacyBindingConfiguration.Standalone, CancellationToken.None);
var result = await testSubject.GetConfigurationAsync(CreateQp(), Language.Cpp, BindingConfiguration.Standalone, CancellationToken.None);

// Assert
result.Should().BeNull();
Expand All @@ -227,7 +227,7 @@ public void GetRules_UnsupportedLanguage_Throws()
var testSubject = CreateTestSubject(serviceMock, testLogger);

// Act
Action act = () => testSubject.GetConfigurationAsync(CreateQp(), Language.VBNET, LegacyBindingConfiguration.Standalone, cts.Token).Wait();
Action act = () => testSubject.GetConfigurationAsync(CreateQp(), Language.VBNET, BindingConfiguration.Standalone, cts.Token).Wait();

// Assert
act.Should().ThrowExactly<AggregateException>().WithInnerException<ArgumentOutOfRangeException>();
Expand Down
Loading

0 comments on commit 4af1c03

Please sign in to comment.