Skip to content

Commit

Permalink
SLVS-1396 Migration wizard: Integrate with the new binding and connec…
Browse files Browse the repository at this point in the history
…tion models (#5700)
  • Loading branch information
gabriela-trutan-sonarsource authored Sep 25, 2024
1 parent 9c754e2 commit ca5fbca
Show file tree
Hide file tree
Showing 14 changed files with 345 additions and 196 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ public class UnintrusiveBindingControllerTests
{
private static readonly CancellationToken ACancellationToken = CancellationToken.None;
private static readonly BasicAuthCredentials ValidToken = new ("TOKEN", new SecureString());
private static readonly BoundSonarQubeProject OldBoundProject = new (new Uri("http://any"), "any", "any");
private static readonly BoundServerProject AnyBoundProject = new ("any", "any", new ServerConnection.SonarCloud("any", credentials: ValidToken));

[TestMethod]
Expand All @@ -48,8 +47,6 @@ public void MefCtor_IUnintrusiveBindingController_CheckIsExported()
{
MefTestHelpers.CheckTypeCanBeImported<UnintrusiveBindingController, IUnintrusiveBindingController>(
MefTestHelpers.CreateExport<IBindingProcessFactory>(),
MefTestHelpers.CreateExport<IServerConnectionsRepository>(),
MefTestHelpers.CreateExport<ISolutionInfoProvider>(),
MefTestHelpers.CreateExport<ISonarQubeService>(),
MefTestHelpers.CreateExport<IActiveSolutionChangedHandler>());
}
Expand All @@ -59,8 +56,6 @@ public void MefCtor_IBindingController_CheckIsExported()
{
MefTestHelpers.CheckTypeCanBeImported<UnintrusiveBindingController, IBindingController>(
MefTestHelpers.CreateExport<IBindingProcessFactory>(),
MefTestHelpers.CreateExport<IServerConnectionsRepository>(),
MefTestHelpers.CreateExport<ISolutionInfoProvider>(),
MefTestHelpers.CreateExport<ISonarQubeService>(),
MefTestHelpers.CreateExport<IActiveSolutionChangedHandler>());
}
Expand Down Expand Up @@ -116,87 +111,12 @@ public async Task BindAsync_CallsBindingProcessInOrder()
bindingProcess.SaveServerExclusionsAsync(cancellationToken);
});
}

[TestMethod]
public async Task BindWithMigrationAsync_OldProject_ConnectionExists_EstablishesBinding()
{
var cancellationToken = CancellationToken.None;
var bindingProcess = Substitute.For<IBindingProcess>();
var bindingProcessFactory = CreateBindingProcessFactory(bindingProcess);
var convertedConnection = ServerConnection.FromBoundSonarQubeProject(OldBoundProject);
var storedConnection = new ServerConnection.SonarQube(new Uri("http://any"));
var serverConnectionsRepository = CreateServerConnectionsRepository(convertedConnection.Id, storedConnection);
var solutionInfoProvider = CreateSolutionInfoProvider();
var testSubject = CreateTestSubject(bindingProcessFactory, serverConnectionsRepository, solutionInfoProvider);

await testSubject.BindWithMigrationAsync(OldBoundProject, null, cancellationToken);

Received.InOrder(() =>
{
serverConnectionsRepository.TryGet(convertedConnection.Id, out Arg.Any<ServerConnection>());
solutionInfoProvider.GetSolutionNameAsync();
bindingProcessFactory.Create(Arg.Is<BindCommandArgs>(b => b.ProjectToBind.ServerProjectKey == OldBoundProject.ProjectKey && b.ProjectToBind.ServerConnection == storedConnection));
bindingProcess.DownloadQualityProfileAsync(null, cancellationToken);
bindingProcess.SaveServerExclusionsAsync(cancellationToken);
});
}

[TestMethod]
public async Task BindWithMigrationAsync_OldProject_ConnectionDoesNotExist_AddsConnectionAndEstablishesBinding()
{
var cancellationToken = CancellationToken.None;
var bindingProcess = Substitute.For<IBindingProcess>();
var bindingProcessFactory = CreateBindingProcessFactory(bindingProcess);
var convertedConnection = ServerConnection.FromBoundSonarQubeProject(OldBoundProject);
var serverConnectionsRepository = CreateServerConnectionsRepository();
serverConnectionsRepository.TryAdd(Arg.Is<ServerConnection>(s => s.Id == convertedConnection.Id)).Returns(true);
var solutionInfoProvider = CreateSolutionInfoProvider();
var testSubject = CreateTestSubject(bindingProcessFactory, serverConnectionsRepository, solutionInfoProvider);

await testSubject.BindWithMigrationAsync(OldBoundProject, null, cancellationToken);

Received.InOrder(() =>
{
serverConnectionsRepository.TryGet(convertedConnection.Id, out Arg.Any<ServerConnection>());
serverConnectionsRepository.TryAdd(Arg.Is<ServerConnection>(c => c.Id == convertedConnection.Id));
solutionInfoProvider.GetSolutionNameAsync();
bindingProcessFactory.Create(Arg.Is<BindCommandArgs>(b => b.ProjectToBind.ServerProjectKey == OldBoundProject.ProjectKey && b.ProjectToBind.ServerConnection.Id == convertedConnection.Id));
bindingProcess.DownloadQualityProfileAsync(null, cancellationToken);
bindingProcess.SaveServerExclusionsAsync(cancellationToken);
});
}

[TestMethod]
public void BindWithMigrationAsync_OldProject_ConnectionDoesNotExist_CannotAdd_Throws()
{
var convertedConnection = ServerConnection.FromBoundSonarQubeProject(OldBoundProject);
var serverConnectionsRepository = CreateServerConnectionsRepository(convertedConnection.Id);
var testSubject = CreateTestSubject(serverConnectionsRepository: serverConnectionsRepository);

Func<Task> act = async () => await testSubject.BindWithMigrationAsync(OldBoundProject, null, CancellationToken.None);

act.Should().Throw<InvalidOperationException>().WithMessage(BindingStrings.UnintrusiveController_CantMigrateConnection);
}

[TestMethod]
public void BindWithMigrationAsync_OldProject_InvalidServerInformation_Throws()
{
var testSubject = CreateTestSubject();

Func<Task> act = async () => await testSubject.BindWithMigrationAsync(new BoundSonarQubeProject(), null, CancellationToken.None);

act.Should().Throw<InvalidOperationException>().WithMessage(BindingStrings.UnintrusiveController_InvalidConnection);
}

private UnintrusiveBindingController CreateTestSubject(IBindingProcessFactory bindingProcessFactory = null,
IServerConnectionsRepository serverConnectionsRepository = null,
ISolutionInfoProvider solutionInfoProvider = null,
ISonarQubeService sonarQubeService = null,
IActiveSolutionChangedHandler activeSolutionChangedHandler = null)
{
var testSubject = new UnintrusiveBindingController(bindingProcessFactory ?? CreateBindingProcessFactory(),
serverConnectionsRepository ?? Substitute.For<IServerConnectionsRepository>(),
solutionInfoProvider ?? Substitute.For<ISolutionInfoProvider>(),
sonarQubeService ?? Substitute.For<ISonarQubeService>(),
activeSolutionChangedHandler ?? Substitute.For<IActiveSolutionChangedHandler>());

Expand All @@ -212,23 +132,4 @@ private static IBindingProcessFactory CreateBindingProcessFactory(IBindingProces

return bindingProcessFactory;
}

private static IServerConnectionsRepository CreateServerConnectionsRepository(string id = null, ServerConnection.SonarQube storedConnection = null)
{
var serverConnectionsRepository = Substitute.For<IServerConnectionsRepository>();
serverConnectionsRepository.TryGet(id ?? Arg.Any<string>(), out Arg.Any<ServerConnection>())
.Returns(info =>
{
info[1] = storedConnection;
return storedConnection != null;
});
return serverConnectionsRepository;
}

private static ISolutionInfoProvider CreateSolutionInfoProvider()
{
var solutionInfoProvider = Substitute.For<ISolutionInfoProvider>();
solutionInfoProvider.GetSolutionNameAsync().Returns("solution");
return solutionInfoProvider;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using System.IO.Abstractions;
using SonarLint.VisualStudio.ConnectedMode.Binding;
using SonarLint.VisualStudio.ConnectedMode.Migration;
using SonarLint.VisualStudio.ConnectedMode.Persistence;
using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Core.Binding;
using SonarLint.VisualStudio.Infrastructure.VS;
using SonarLint.VisualStudio.TestInfrastructure;
using SonarQube.Client.Helpers;

Expand All @@ -34,7 +32,6 @@ namespace SonarLint.VisualStudio.ConnectedMode.UnitTests.Migration;
public class BindingToConnectionMigrationTests
{
private BindingToConnectionMigration testSubject;
private IFileSystem fileSystem;
private IServerConnectionsRepository serverConnectionsRepository;
private ILegacySolutionBindingRepository legacyBindingRepository;
private IUnintrusiveBindingPathProvider unintrusiveBindingPathProvider;
Expand All @@ -45,7 +42,6 @@ public class BindingToConnectionMigrationTests
[TestInitialize]
public void TestInitialize()
{
fileSystem = Substitute.For<IFileSystem>();
serverConnectionsRepository = Substitute.For<IServerConnectionsRepository>();
legacyBindingRepository = Substitute.For<ILegacySolutionBindingRepository>();
solutionBindingRepository = Substitute.For<ISolutionBindingRepository>();
Expand All @@ -54,7 +50,6 @@ public void TestInitialize()
threadHandling = new NoOpThreadHandler();

testSubject = new BindingToConnectionMigration(
fileSystem,
serverConnectionsRepository,
legacyBindingRepository,
solutionBindingRepository,
Expand Down Expand Up @@ -85,27 +80,26 @@ public async Task MigrateBindingToServerConnectionIfNeeded_RunsOnBackgroundThrea
{
var mockedThreadHandling = Substitute.For<IThreadHandling>();
var migrateBindingToServer = new BindingToConnectionMigration(
fileSystem,
serverConnectionsRepository,
legacyBindingRepository,
solutionBindingRepository,
unintrusiveBindingPathProvider,
mockedThreadHandling,
logger);

await migrateBindingToServer.MigrateBindingToServerConnectionIfNeededAsync();
await migrateBindingToServer.MigrateAllBindingsToServerConnectionsIfNeededAsync();

mockedThreadHandling.ReceivedCalls().Should().Contain(call => call.GetMethodInfo().Name == nameof(IThreadHandling.RunOnBackgroundThread));
}

[TestMethod]
public async Task MigrateBindingToServerConnectionIfNeeded_ConnectionsStorageFileExists_ShouldNotMigrate()
{
fileSystem.File.Exists(serverConnectionsRepository.ConnectionsStorageFilePath).Returns(true);
serverConnectionsRepository.ConnectionsFileExists().Returns(true);

await testSubject.MigrateBindingToServerConnectionIfNeededAsync();
await testSubject.MigrateAllBindingsToServerConnectionsIfNeededAsync();

fileSystem.File.Received(1).Exists(serverConnectionsRepository.ConnectionsStorageFilePath);
serverConnectionsRepository.Received(1).ConnectionsFileExists();
serverConnectionsRepository.DidNotReceiveWithAnyArgs().TryAdd(default);
unintrusiveBindingPathProvider.DidNotReceive().GetBindingPaths();
}
Expand All @@ -115,11 +109,11 @@ public async Task MigrateBindingToServerConnectionIfNeeded_ConnectionsStorageDoe
{
CreateTwoBindingPathsToMockedBoundProject();

await testSubject.MigrateBindingToServerConnectionIfNeededAsync();
await testSubject.MigrateAllBindingsToServerConnectionsIfNeededAsync();

Received.InOrder(() =>
{
fileSystem.File.Exists(serverConnectionsRepository.ConnectionsStorageFilePath);
serverConnectionsRepository.ConnectionsFileExists();
logger.WriteLine(MigrationStrings.ConnectionMigration_StartMigration);
unintrusiveBindingPathProvider.GetBindingPaths();
serverConnectionsRepository.TryAdd(Arg.Any<ServerConnection>());
Expand All @@ -132,7 +126,7 @@ public async Task MigrateBindingToServerConnectionIfNeeded_MigrationIsExecuted_C
{
var boundProjects = CreateTwoBindingPathsToMockedBoundProject().Values.ToList();

await testSubject.MigrateBindingToServerConnectionIfNeededAsync();
await testSubject.MigrateAllBindingsToServerConnectionsIfNeededAsync();

serverConnectionsRepository.Received(1).TryAdd(Arg.Is<ServerConnection>(conn => conn.Id == boundProjects[0].ServerUri.ToString()));
serverConnectionsRepository.Received(1).TryAdd(Arg.Is<ServerConnection>(conn => conn.Id == boundProjects[1].ServerUri.ToString()));
Expand All @@ -143,7 +137,7 @@ public async Task MigrateBindingToServerConnectionIfNeeded_MigrationIsExecuted_U
{
var bindingPathToBoundProjectDictionary = CreateTwoBindingPathsToMockedBoundProject();

await testSubject.MigrateBindingToServerConnectionIfNeededAsync();
await testSubject.MigrateAllBindingsToServerConnectionsIfNeededAsync();

CheckBindingsWereMigrated(bindingPathToBoundProjectDictionary);
}
Expand All @@ -157,7 +151,7 @@ public async Task MigrateBindingToServerConnectionIfNeeded_MigrationIsExecutedFo
serverConnectionsRepository.TryGet(expectedServerConnectionId, out _).Returns(true);


await testSubject.MigrateBindingToServerConnectionIfNeededAsync();
await testSubject.MigrateAllBindingsToServerConnectionsIfNeededAsync();

logger.Received(1).WriteLine(string.Format(MigrationStrings.ConnectionMigration_ExistingServerConnectionNotMigrated, expectedServerConnectionId));
serverConnectionsRepository.DidNotReceive().TryAdd(Arg.Is<ServerConnection>(conn => conn.Id == expectedServerConnectionId));
Expand All @@ -171,7 +165,7 @@ public async Task MigrateBindingToServerConnectionIfNeeded_ReadingBindingReturns
var bindingPathToExclude = boundProjects.Keys.First();
legacyBindingRepository.Read(Arg.Is<string>(path => path == bindingPathToExclude)).Returns((BoundSonarQubeProject)null);

await testSubject.MigrateBindingToServerConnectionIfNeededAsync();
await testSubject.MigrateAllBindingsToServerConnectionsIfNeededAsync();

logger.Received(1).WriteLine(string.Format(MigrationStrings.ConnectionMigration_BindingNotMigrated, bindingPathToExclude, "legacyBoundProject was not found"));
serverConnectionsRepository.DidNotReceive().TryAdd(Arg.Is<ServerConnection>(conn => IsExpectedServerConnection(conn, boundProjects.First().Value)));
Expand All @@ -184,7 +178,7 @@ public async Task MigrateBindingToServerConnectionIfNeeded_MigratingConnectionFa
var boundPathToBoundProject = CreateTwoBindingPathsToMockedBoundProject().First();
serverConnectionsRepository.TryAdd(Arg.Is<ServerConnection>(conn => IsExpectedServerConnection(conn, boundPathToBoundProject.Value))).Returns(false);

await testSubject.MigrateBindingToServerConnectionIfNeededAsync();
await testSubject.MigrateAllBindingsToServerConnectionsIfNeededAsync();

logger.Received(1).WriteLine(string.Format(MigrationStrings.ConnectionMigration_ServerConnectionNotMigrated, boundPathToBoundProject.Value.ServerUri));
serverConnectionsRepository.Received(1).TryAdd(Arg.Is<ServerConnection>(conn => IsExpectedServerConnection(conn, boundPathToBoundProject.Value)));
Expand All @@ -196,7 +190,7 @@ public async Task MigrateBindingToServerConnectionIfNeeded_MigrationIsExecuted_C
{
var boundProjects = CreateTwoBindingPathsToMockedBoundProject().Values.ToList();

await testSubject.MigrateBindingToServerConnectionIfNeededAsync();
await testSubject.MigrateAllBindingsToServerConnectionsIfNeededAsync();

CheckCredentialsAreLoaded(boundProjects[0]);
CheckCredentialsAreLoaded(boundProjects[1]);
Expand All @@ -209,7 +203,7 @@ public async Task MigrateBindingToServerConnectionIfNeeded_MigrationThrowsExcept
var errorMessage = "loading failed";
solutionBindingRepository.When(repo => repo.Write(Arg.Any<string>(), Arg.Any<BoundServerProject>())).Throw(new Exception(errorMessage));

await testSubject.MigrateBindingToServerConnectionIfNeededAsync();
await testSubject.MigrateAllBindingsToServerConnectionsIfNeededAsync();

logger.Received(1).WriteLine(string.Format(MigrationStrings.ConnectionMigration_BindingNotMigrated, boundProjects.First().Key, errorMessage));
logger.Received(1).WriteLine(string.Format(MigrationStrings.ConnectionMigration_BindingNotMigrated, boundProjects.Last().Key, errorMessage));
Expand Down
Loading

0 comments on commit ca5fbca

Please sign in to comment.