Skip to content

Commit

Permalink
Fix MuteIssuesService should use ServerIssueStore.AddIssues instead o…
Browse files Browse the repository at this point in the history
…f UpdateIssues
  • Loading branch information
georgii-borovinskikh-sonarsource committed Dec 11, 2023
1 parent a90e1c2 commit fa51395
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 31 deletions.
38 changes: 24 additions & 14 deletions src/ConnectedMode.UnitTests/Transition/MuteIssuesServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public async Task Mute_NotInConnectedMode_Logs()

var testSubject = CreateTestSubject(activeSolutionBoundTracker: activeSolutionBoundTracker, logger: logger.Object, threadHandling: threadHandling.Object);

await testSubject.Mute("anyKEy", CancellationToken.None);
await testSubject.Mute(CreateServerIssue(), CancellationToken.None);

logger.Verify(l => l.LogVerbose("[Transition]Issue muting is only supported in connected mode"), Times.Once);
threadHandling.Verify(t => t.ThrowIfOnUIThread(), Times.Once());
Expand All @@ -73,38 +73,42 @@ public async Task Mute_NotInConnectedMode_Logs()
[TestMethod]
public async Task Mute_WindowOK_CallService()
{
var sonarQubeIssue = CreateServerIssue();
sonarQubeIssue.IsResolved.Should().BeFalse();

var threadHandling = CreateThreadHandling();
var muteIssuesWindowService = CreateMuteIssuesWindowService("issueKey", true, SonarQubeIssueTransition.FalsePositive, "some comment");
var muteIssuesWindowService = CreateMuteIssuesWindowService(true, SonarQubeIssueTransition.FalsePositive, "some comment");

var sonarQubeService = new Mock<ISonarQubeService>();

sonarQubeService.Setup(s => s.TransitionIssueAsync(It.IsAny<string>(), It.IsAny<SonarQubeIssueTransition>(), It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(SonarQubeIssueTransitionResult.FailedToTransition);
sonarQubeService.Setup(s => s.TransitionIssueAsync("issueKey", SonarQubeIssueTransition.FalsePositive, "some comment", CancellationToken.None)).ReturnsAsync(SonarQubeIssueTransitionResult.Success);
sonarQubeService.Setup(s => s.TransitionIssueAsync(sonarQubeIssue.IssueKey, SonarQubeIssueTransition.FalsePositive, "some comment", CancellationToken.None)).ReturnsAsync(SonarQubeIssueTransitionResult.Success);

var serverIssuesStore = new Mock<IServerIssuesStoreWriter>();

var testSubject = CreateTestSubject(muteIssuesWindowService: muteIssuesWindowService.Object, sonarQubeService: sonarQubeService.Object, serverIssuesStore: serverIssuesStore.Object, threadHandling: threadHandling.Object);

await testSubject.Mute("issueKey", CancellationToken.None);
await testSubject.Mute(sonarQubeIssue, CancellationToken.None);

muteIssuesWindowService.Verify(s => s.Show("issueKey"), Times.Once);
sonarQubeService.Verify(s => s.TransitionIssueAsync("issueKey", SonarQubeIssueTransition.FalsePositive, "some comment", CancellationToken.None), Times.Once);
serverIssuesStore.Verify(s => s.UpdateIssues(true, It.Is<IEnumerable<string>>(p => p.SequenceEqual(new[] { "issueKey" }))), Times.Once);
muteIssuesWindowService.Verify(s => s.Show(), Times.Once);
sonarQubeService.Verify(s => s.TransitionIssueAsync(sonarQubeIssue.IssueKey, SonarQubeIssueTransition.FalsePositive, "some comment", CancellationToken.None), Times.Once);
serverIssuesStore.Verify(s => s.AddIssues(It.Is<IEnumerable<SonarQubeIssue>>(p => p.SequenceEqual(new[] { sonarQubeIssue })), false), Times.Once);
threadHandling.Verify(t => t.ThrowIfOnUIThread(), Times.Once());
sonarQubeIssue.IsResolved.Should().BeTrue();
}

[TestMethod]
public async Task Mute_WindowCancel_DontCallService()
{
var muteIssuesWindowService = CreateMuteIssuesWindowService("issueKey", false, SonarQubeIssueTransition.FalsePositive, "some comment");
var muteIssuesWindowService = CreateMuteIssuesWindowService(false, SonarQubeIssueTransition.FalsePositive, "some comment");

var sonarQubeService = new Mock<ISonarQubeService>();

var testSubject = CreateTestSubject(muteIssuesWindowService: muteIssuesWindowService.Object, sonarQubeService: sonarQubeService.Object);

await testSubject.Mute("issueKey", CancellationToken.None);
await testSubject.Mute(CreateServerIssue(), CancellationToken.None);

muteIssuesWindowService.Verify(s => s.Show("issueKey"), Times.Once);
muteIssuesWindowService.Verify(s => s.Show(), Times.Once);
sonarQubeService.VerifyNoOtherCalls();
}

Expand All @@ -115,25 +119,25 @@ public async Task Mute_WindowCancel_DontCallService()
public async Task Mute_SQError_ShowsError(SonarQubeIssueTransitionResult result, string errorMessage)
{
var messageBox = new Mock<IMessageBox>();
var muteIssuesWindowService = CreateMuteIssuesWindowService("issueKey", true, SonarQubeIssueTransition.FalsePositive, "some comment");
var muteIssuesWindowService = CreateMuteIssuesWindowService(true, SonarQubeIssueTransition.FalsePositive, "some comment");

var sonarQubeService = new Mock<ISonarQubeService>();

sonarQubeService.Setup(s => s.TransitionIssueAsync(It.IsAny<string>(), It.IsAny<SonarQubeIssueTransition>(), It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(result);

var testSubject = CreateTestSubject(muteIssuesWindowService: muteIssuesWindowService.Object, sonarQubeService: sonarQubeService.Object, messageBox: messageBox.Object);

await testSubject.Mute("issueKey", CancellationToken.None);
await testSubject.Mute(CreateServerIssue(), CancellationToken.None);

messageBox.Verify(mb => mb.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error));
}

private Mock<IMuteIssuesWindowService> CreateMuteIssuesWindowService(string issueKey, bool result, SonarQubeIssueTransition transition = default, string comment = default)
private Mock<IMuteIssuesWindowService> CreateMuteIssuesWindowService(bool result, SonarQubeIssueTransition transition = default, string comment = default)
{
var muteIssuesWindowResponse = CreateMuteIssuesWindowResponse(result, transition, comment);

var service = new Mock<IMuteIssuesWindowService>();
service.Setup(s => s.Show(issueKey)).Returns(muteIssuesWindowResponse);
service.Setup(s => s.Show()).Returns(muteIssuesWindowResponse);

return service;

Expand Down Expand Up @@ -190,5 +194,11 @@ private MuteIssuesService CreateTestSubject(IActiveSolutionBoundTracker activeSo

return new MuteIssuesService(activeSolutionBoundTracker, logger, muteIssuesWindowService, sonarQubeService, serverIssuesStore, threadHandling, messageBox);
}

private static SonarQubeIssue CreateServerIssue()
{
return new SonarQubeIssue("testKey", "test", "test", "test", "test", "test", false, SonarQubeIssueSeverity.Info,
DateTimeOffset.MinValue, DateTimeOffset.MinValue, null, null);
}
}
}
14 changes: 8 additions & 6 deletions src/ConnectedMode/Transition/MuteIssuesService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ internal MuteIssuesService(IActiveSolutionBoundTracker activeSolutionBoundTracke
resourceManager = new ResourceManager(typeof(Resources));
}

public async Task Mute(string issueKey, CancellationToken token)
public async Task Mute(SonarQubeIssue issue, CancellationToken token)
{
threadHandling.ThrowIfOnUIThread();

Expand All @@ -82,17 +82,19 @@ public async Task Mute(string issueKey, CancellationToken token)

MuteIssuesWindowResponse windowResponse = default;

await threadHandling.RunOnUIThreadAsync(() => windowResponse = muteIssuesWindowService.Show(issueKey));
await threadHandling.RunOnUIThreadAsync(() => windowResponse = muteIssuesWindowService.Show());

if (windowResponse.Result)
{
var serviceResult = await sonarQubeService.TransitionIssueAsync(issueKey, windowResponse.IssueTransition, windowResponse.Comment, token);
var serviceResult = await sonarQubeService.TransitionIssueAsync(issue.IssueKey, windowResponse.IssueTransition, windowResponse.Comment, token);

if (serviceResult == SonarQubeIssueTransitionResult.Success)
if (serviceResult == SonarQubeIssueTransitionResult.Success || serviceResult == SonarQubeIssueTransitionResult.CommentAdditionFailed)
{
serverIssuesStore.UpdateIssues(true, new[] { issueKey });
issue.IsResolved = true;
serverIssuesStore.AddIssues(new[] { issue }, false);
}
else

if (serviceResult != SonarQubeIssueTransitionResult.Success)
{
messageBox.Show(resourceManager.GetString($"MuteIssuesService_Error_{serviceResult}"), Resources.MuteIssuesService_Error_Caption, MessageBoxButton.OK, MessageBoxImage.Error);
}
Expand Down
3 changes: 2 additions & 1 deletion src/Core/Transition/IMuteIssuesService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@

using System.Threading;
using System.Threading.Tasks;
using SonarQube.Client.Models;

namespace SonarLint.VisualStudio.Core.Transition
{
public interface IMuteIssuesService
{
Task Mute(string issueKey, CancellationToken token);
Task Mute(SonarQubeIssue issue, CancellationToken token);
}
}
27 changes: 27 additions & 0 deletions src/Core/Transition/IMuteIssuesWindowService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* SonarLint for Visual Studio
* Copyright (C) 2016-2023 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.
*/

namespace SonarLint.VisualStudio.Core.Transition
{
public interface IMuteIssuesWindowService
{
MuteIssuesWindowResponse Show();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@

namespace SonarLint.VisualStudio.Core.Transition
{
public interface IMuteIssuesWindowService
{
MuteIssuesWindowResponse Show(string issueKey);
}

public class MuteIssuesWindowResponse
{
public bool Result { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public void Execute_MutesIssue()
errorListHelperMock.Verify(x => x.TryGetIssueFromSelectedRow(out issue), Times.Once);
threadHandlingMock.Verify(x => x.RunOnBackgroundThread(It.IsAny<Func<Task<bool>>>()), Times.Once);
serverIssueFinderMock.Verify(x => x.FindServerIssueAsync(issue, It.IsAny<CancellationToken>()), Times.Once);
muteIssueServiceMock.Verify(x => x.Mute(sonarQubeIssue.IssueKey, It.IsAny<CancellationToken>()), Times.Once);
muteIssueServiceMock.Verify(x => x.Mute(sonarQubeIssue, It.IsAny<CancellationToken>()), Times.Once);
}

[TestMethod]
Expand Down Expand Up @@ -248,7 +248,7 @@ public void Execute_RoslynIssue_IsMuted()
threadHandlingMock.Verify(x => x.RunOnBackgroundThread(It.IsAny<Func<Task<bool>>>()), Times.Once);
roslynIssueLineHashCalculatorMock.Verify(x => x.UpdateRoslynIssueWithLineHash(roslynIssue), Times.Once);
serverIssueFinderMock.Verify(x => x.FindServerIssueAsync(roslynIssue, It.IsAny<CancellationToken>()), Times.Once);
muteIssueServiceMock.Verify(x => x.Mute(sonarQubeIssue.IssueKey, It.IsAny<CancellationToken>()), Times.Once);
muteIssueServiceMock.Verify(x => x.Mute(sonarQubeIssue, It.IsAny<CancellationToken>()), Times.Once);
}

[TestMethod]
Expand Down Expand Up @@ -295,7 +295,7 @@ private static void SetUpIssueMuting(Mock<IServerIssueFinder> serverIssueFinderM
.ReturnsAsync(sonarQubeIssue);
muteIssueServiceMock
.InSequence(callSequence)
.Setup(x => x.Mute(sonarQubeIssue.IssueKey, It.IsAny<CancellationToken>()))
.Setup(x => x.Mute(sonarQubeIssue, It.IsAny<CancellationToken>()))
.Returns(Task.CompletedTask);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Integration.Vsix/Analysis/MuteIssueCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ private async Task<bool> MuteIssueAsync(IFilterableIssue issue)
return false;
}

await muteIssuesService.Mute(serverIssue.IssueKey, CancellationToken.None);
await muteIssuesService.Mute(serverIssue, CancellationToken.None);
logger.WriteLine(AnalysisStrings.MuteIssue_HaveMuted, serverIssue.IssueKey);

return true;
Expand Down
2 changes: 1 addition & 1 deletion src/Integration/Transition/MuteIssuesWindowService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public MuteIssuesWindowService(IConnectedModeFeaturesConfiguration connectedMode
}

[ExcludeFromCodeCoverage]
public MuteIssuesWindowResponse Show(string issueKey)
public MuteIssuesWindowResponse Show()
{
var dialog = new MuteWindowDialog(connectedModeFeaturesConfiguration.IsAcceptTransitionAvailable());
dialog.Owner = Application.Current.MainWindow;
Expand Down

0 comments on commit fa51395

Please sign in to comment.