Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SLVS-1396 Migration wizard: Integrate with the new binding and connection models #5700

Merged
Merged
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.IsConnectionsFileExisting().Returns(true);

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

fileSystem.File.Received(1).Exists(serverConnectionsRepository.ConnectionsStorageFilePath);
serverConnectionsRepository.Received(1).IsConnectionsFileExisting();
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.IsConnectionsFileExisting();
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