diff --git a/src/CFamily.UnitTests/Subprocess/ProcessRunnerTests.cs b/src/CFamily.UnitTests/Subprocess/ProcessRunnerTests.cs index d8c566e61..f005e32df 100644 --- a/src/CFamily.UnitTests/Subprocess/ProcessRunnerTests.cs +++ b/src/CFamily.UnitTests/Subprocess/ProcessRunnerTests.cs @@ -18,14 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; using SonarLint.VisualStudio.CFamily.Helpers.UnitTests; using SonarLint.VisualStudio.Core; using SonarLint.VisualStudio.TestInfrastructure; @@ -394,7 +387,6 @@ xxx yyy } [TestMethod] - [Ignore] // https://sonarsource.atlassian.net/browse/SLVS-1428 public void Execute_CancellationTokenCancelledMidway_CancelledDuringWritingRequest_ProcessKilled() { var exeName = WriteBatchFileForTest(TestContext, @" @@ -492,7 +484,7 @@ private static void AssertTextDoesNotAppearInLog(string text, TestLogger logger) private static string WriteBatchFileForTest(TestContext context, string content) { var testPath = CreateTestSpecificFolder(context); - var fileName = Path.Combine(testPath, context.TestName + ".bat"); + var fileName = Path.Combine(testPath, "test.bat"); File.Exists(fileName).Should().BeFalse("Not expecting a batch file to already exist: {0}", fileName); File.WriteAllText(fileName, content); return fileName; diff --git a/src/ConnectedMode.UnitTests/Persistence/BindingDtoConverterTests.cs b/src/ConnectedMode.UnitTests/Persistence/BindingJsonModelConverterTests.cs similarity index 57% rename from src/ConnectedMode.UnitTests/Persistence/BindingDtoConverterTests.cs rename to src/ConnectedMode.UnitTests/Persistence/BindingJsonModelConverterTests.cs index a26a6fa6e..c32905086 100644 --- a/src/ConnectedMode.UnitTests/Persistence/BindingDtoConverterTests.cs +++ b/src/ConnectedMode.UnitTests/Persistence/BindingJsonModelConverterTests.cs @@ -27,33 +27,33 @@ namespace SonarLint.VisualStudio.ConnectedMode.UnitTests.Persistence; [TestClass] -public class BindingDtoConverterTests +public class BindingJsonModelConverterTests { - private BindingDtoConverter testSubject; + private BindingJsonModelConverter testSubject; [TestInitialize] public void TestInitialize() { - testSubject = new BindingDtoConverter(); + testSubject = new BindingJsonModelConverter(); } [TestMethod] public void MefCtor_CheckIsExported() { - MefTestHelpers.CheckTypeCanBeImported(); + MefTestHelpers.CheckTypeCanBeImported(); } [TestMethod] public void MefCtor_CheckIsSingleton() { - MefTestHelpers.CheckIsSingletonMefComponent(); + MefTestHelpers.CheckIsSingletonMefComponent(); } [TestMethod] - public void ConvertFromDto_ConvertsCorrectly() + public void ConvertFromModel_ConvertsCorrectly() { const string localBindingKey = "solution123"; - var bindingDto = new BindingDto + var bindingModel = new BindingJsonModel { ProjectKey = "project123", Profiles = new Dictionary(), @@ -64,55 +64,55 @@ public void ConvertFromDto_ConvertsCorrectly() }; var connection = new ServerConnection.SonarCloud("myorg"); - var boundServerProject = testSubject.ConvertFromDto(bindingDto, connection, localBindingKey); + var boundServerProject = testSubject.ConvertFromModel(bindingModel, connection, localBindingKey); boundServerProject.ServerConnection.Should().BeSameAs(connection); boundServerProject.LocalBindingKey.Should().BeSameAs(localBindingKey); - boundServerProject.ServerProjectKey.Should().BeSameAs(bindingDto.ProjectKey); - boundServerProject.Profiles.Should().BeSameAs(bindingDto.Profiles); + boundServerProject.ServerProjectKey.Should().BeSameAs(bindingModel.ProjectKey); + boundServerProject.Profiles.Should().BeSameAs(bindingModel.Profiles); } [TestMethod] - public void ConvertToDto_SonarCloudConnection_ConvertsCorrectly() + public void ConvertToModel_SonarCloudConnection_ConvertsCorrectly() { var boundServerProject = new BoundServerProject("localBinding", "serverProject", new ServerConnection.SonarCloud("myorg")) { Profiles = new Dictionary() }; - var bindingDto = testSubject.ConvertToDto(boundServerProject); + var bindingModel = testSubject.ConvertToModel(boundServerProject); - bindingDto.ProjectKey.Should().BeSameAs(boundServerProject.ServerProjectKey); - bindingDto.ProjectName.Should().BeNull(); - bindingDto.ServerUri.Should().BeEquivalentTo(boundServerProject.ServerConnection.ServerUri); - bindingDto.Organization.Key.Should().BeSameAs(((ServerConnection.SonarCloud)boundServerProject.ServerConnection).OrganizationKey); - bindingDto.ServerConnectionId.Should().BeSameAs(boundServerProject.ServerConnection.Id); - bindingDto.Profiles.Should().BeSameAs(boundServerProject.Profiles); + bindingModel.ProjectKey.Should().BeSameAs(boundServerProject.ServerProjectKey); + bindingModel.ProjectName.Should().BeNull(); + bindingModel.ServerUri.Should().BeEquivalentTo(boundServerProject.ServerConnection.ServerUri); + bindingModel.Organization.Key.Should().BeSameAs(((ServerConnection.SonarCloud)boundServerProject.ServerConnection).OrganizationKey); + bindingModel.ServerConnectionId.Should().BeSameAs(boundServerProject.ServerConnection.Id); + bindingModel.Profiles.Should().BeSameAs(boundServerProject.Profiles); } [TestMethod] - public void ConvertToDto_SonarQubeConnection_ConvertsCorrectly() + public void ConvertToModel_SonarQubeConnection_ConvertsCorrectly() { var boundServerProject = new BoundServerProject("localBinding", "serverProject", new ServerConnection.SonarQube(new Uri("http://mysq"))) { Profiles = new Dictionary() }; - var bindingDto = testSubject.ConvertToDto(boundServerProject); + var bindingModel = testSubject.ConvertToModel(boundServerProject); - bindingDto.ProjectKey.Should().BeSameAs(boundServerProject.ServerProjectKey); - bindingDto.ProjectName.Should().BeNull(); - bindingDto.ServerUri.Should().BeEquivalentTo(boundServerProject.ServerConnection.ServerUri); - bindingDto.Organization.Should().BeNull(); - bindingDto.ServerConnectionId.Should().BeSameAs(boundServerProject.ServerConnection.Id); - bindingDto.Profiles.Should().BeSameAs(boundServerProject.Profiles); + bindingModel.ProjectKey.Should().BeSameAs(boundServerProject.ServerProjectKey); + bindingModel.ProjectName.Should().BeNull(); + bindingModel.ServerUri.Should().BeEquivalentTo(boundServerProject.ServerConnection.ServerUri); + bindingModel.Organization.Should().BeNull(); + bindingModel.ServerConnectionId.Should().BeSameAs(boundServerProject.ServerConnection.Id); + bindingModel.Profiles.Should().BeSameAs(boundServerProject.Profiles); } [TestMethod] - public void ConvertFromDtoToLegacy_ConvertsCorrectly() + public void ConvertFromModelToLegacy_ConvertsCorrectly() { var credentials = Substitute.For(); - var bindingDto = new BindingDto + var bindingModel = new BindingJsonModel { Organization = new SonarQubeOrganization("org", "my org"), ServerUri = new Uri("http://localhost"), @@ -122,12 +122,12 @@ public void ConvertFromDtoToLegacy_ConvertsCorrectly() ServerConnectionId = "ignored", }; - var legacyBinding = testSubject.ConvertFromDtoToLegacy(bindingDto, credentials); + var legacyBinding = testSubject.ConvertFromModelToLegacy(bindingModel, credentials); - legacyBinding.ProjectKey.Should().BeSameAs(bindingDto.ProjectKey); - legacyBinding.ProjectName.Should().BeSameAs(bindingDto.ProjectName); - legacyBinding.ServerUri.Should().BeSameAs(bindingDto.ServerUri); - legacyBinding.Organization.Should().BeSameAs(bindingDto.Organization); + legacyBinding.ProjectKey.Should().BeSameAs(bindingModel.ProjectKey); + legacyBinding.ProjectName.Should().BeSameAs(bindingModel.ProjectName); + legacyBinding.ServerUri.Should().BeSameAs(bindingModel.ServerUri); + legacyBinding.Organization.Should().BeSameAs(bindingModel.Organization); legacyBinding.Profiles.Should().BeSameAs(legacyBinding.Profiles); legacyBinding.Credentials.Should().BeSameAs(credentials); } diff --git a/src/ConnectedMode.UnitTests/Persistence/BindingDtoSerializationTests.cs b/src/ConnectedMode.UnitTests/Persistence/BindingJsonModelSerializationTests.cs similarity index 56% rename from src/ConnectedMode.UnitTests/Persistence/BindingDtoSerializationTests.cs rename to src/ConnectedMode.UnitTests/Persistence/BindingJsonModelSerializationTests.cs index 47b75c6f4..ac0bd7404 100644 --- a/src/ConnectedMode.UnitTests/Persistence/BindingDtoSerializationTests.cs +++ b/src/ConnectedMode.UnitTests/Persistence/BindingJsonModelSerializationTests.cs @@ -27,7 +27,7 @@ namespace SonarLint.VisualStudio.ConnectedMode.UnitTests.Persistence; [TestClass] -public class BindingDtoSerializationTests +public class BindingJsonModelSerializationTests { private static readonly DateTime Date = new DateTime(2020, 12, 31, 23, 59, 59); @@ -44,7 +44,7 @@ public class BindingDtoSerializationTests Profiles = QualityProfiles }; - private readonly BindingDto bindingDto = new() + private readonly BindingJsonModel bindingJsonModel = new() { ServerUri = new Uri("http://next.sonarqube.com/sonarqube"), ProjectKey = "my_project_123", @@ -57,12 +57,12 @@ public class BindingDtoSerializationTests private readonly BoundServerProject boundSonarCloudServerProject = new("solution123", "my_project_123", new ServerConnection.SonarCloud("org_key_123")){ Profiles = QualityProfiles }; private readonly BoundServerProject boundSonarQubeServerProject = new("solution123", "my_project_123", new ServerConnection.SonarQube(new Uri("http://next.sonarqube.com/sonarqube"))){ Profiles = QualityProfiles }; - private readonly BindingDtoConverter bindingDtoConverter = new(); + private readonly BindingJsonModelConverter bindingJsonModelConverter = new(); [TestMethod] - public void Dto_SerializedAsExpected() + public void JsonModel_SerializedAsExpected() { - var serializeObject = JsonConvert.SerializeObject(bindingDto, Formatting.Indented); + var serializeObject = JsonConvert.SerializeObject(bindingJsonModel, Formatting.Indented); serializeObject.Should().BeEquivalentTo( """ @@ -86,9 +86,9 @@ public void Dto_SerializedAsExpected() } [TestMethod] - public void Dto_FromSonarCloudBinding_SerializedAsExpected() + public void JsonModel_FromSonarCloudBinding_SerializedAsExpected() { - var serializeObject = JsonConvert.SerializeObject(bindingDtoConverter.ConvertToDto(boundSonarCloudServerProject), Formatting.Indented); + var serializeObject = JsonConvert.SerializeObject(bindingJsonModelConverter.ConvertToModel(boundSonarCloudServerProject), Formatting.Indented); serializeObject.Should().BeEquivalentTo( """ @@ -111,9 +111,9 @@ public void Dto_FromSonarCloudBinding_SerializedAsExpected() } [TestMethod] - public void Dto_FromSonarQubeBinding_SerializedAsExpected() + public void JsonModel_FromSonarQubeBinding_SerializedAsExpected() { - var serializeObject = JsonConvert.SerializeObject(bindingDtoConverter.ConvertToDto(boundSonarQubeServerProject), Formatting.Indented); + var serializeObject = JsonConvert.SerializeObject(bindingJsonModelConverter.ConvertToModel(boundSonarQubeServerProject), Formatting.Indented); serializeObject.Should().BeEquivalentTo( """ @@ -132,56 +132,56 @@ public void Dto_FromSonarQubeBinding_SerializedAsExpected() } [TestMethod] - public void Legacy_ToJson_ToDto_ToLegacy_IsCorrect() + public void Legacy_ToJson_ToJsonModel_ToLegacy_IsCorrect() { var serialized = JsonConvert.SerializeObject(boundSonarQubeProject); - var deserializeBindingDto = JsonConvert.DeserializeObject(serialized); + var deserializeBindingModel = JsonConvert.DeserializeObject(serialized); - var convertedFromDtoToLegacy = bindingDtoConverter.ConvertFromDtoToLegacy(deserializeBindingDto, null); + var convertedFromJsonToLegacy = bindingJsonModelConverter.ConvertFromModelToLegacy(deserializeBindingModel, null); - convertedFromDtoToLegacy.Should().BeEquivalentTo(boundSonarQubeProject); + convertedFromJsonToLegacy.Should().BeEquivalentTo(boundSonarQubeProject); } [TestMethod] - public void Legacy_ToJson_ToLegacyDirectly_And_ToDto_ToLegacy_IsCorrect() + public void Legacy_ToJson_ToLegacyDirectly_And_ToJsonModel_ToLegacy_IsCorrect() { var serializedLegacy = JsonConvert.SerializeObject(boundSonarQubeProject); var legacyDirect = JsonConvert.DeserializeObject(serializedLegacy); - var deserializedBindingDto = JsonConvert.DeserializeObject(serializedLegacy); + var deserializedBindingModel = JsonConvert.DeserializeObject(serializedLegacy); - var convertedFromDtoToLegacy = bindingDtoConverter.ConvertFromDtoToLegacy(deserializedBindingDto, null); + var convertedFromJsonToLegacy = bindingJsonModelConverter.ConvertFromModelToLegacy(deserializedBindingModel, null); - convertedFromDtoToLegacy.Should().BeEquivalentTo(legacyDirect); + convertedFromJsonToLegacy.Should().BeEquivalentTo(legacyDirect); } [TestMethod] - public void Dto_ToJson_ToLegacy_IsCorrect() + public void JsonModel_ToJson_ToLegacy_IsCorrect() { - var serializedBindingDto = JsonConvert.SerializeObject(bindingDto); - var convertedFromDtoToLegacy = JsonConvert.DeserializeObject(serializedBindingDto); + var serializedBindingModel = JsonConvert.SerializeObject(bindingJsonModel); + var convertedFromJsonToLegacy = JsonConvert.DeserializeObject(serializedBindingModel); - convertedFromDtoToLegacy.Should().BeEquivalentTo(boundSonarQubeProject); + convertedFromJsonToLegacy.Should().BeEquivalentTo(boundSonarQubeProject); } [TestMethod] - public void Dto_ToJson_ToDto_ToLegacy_IsCorrect() + public void JsonModel_ToJson_ToJsonModel_ToLegacy_IsCorrect() { - var serializedBindingDto = JsonConvert.SerializeObject(bindingDto); - var deserializedBindingDto = JsonConvert.DeserializeObject(serializedBindingDto); + var serializedBindingModel = JsonConvert.SerializeObject(bindingJsonModel); + var deserializedBindingModel = JsonConvert.DeserializeObject(serializedBindingModel); - var convertedFromDtoToLegacy = bindingDtoConverter.ConvertFromDtoToLegacy(deserializedBindingDto, null); + var convertedFromJsonToLegacy = bindingJsonModelConverter.ConvertFromModelToLegacy(deserializedBindingModel, null); - convertedFromDtoToLegacy.Should().BeEquivalentTo(boundSonarQubeProject); + convertedFromJsonToLegacy.Should().BeEquivalentTo(boundSonarQubeProject); } [TestMethod] - public void CurrentSonarCloud_ToDto_ToJson_ToDto_ToLegacy_IsCorrect() + public void CurrentSonarCloud_ToJsonModel_ToJson_ToJsonModel_ToLegacy_IsCorrect() { - var convertedBindingDtoFromLegacy = bindingDtoConverter.ConvertToDto(boundSonarCloudServerProject); - var serializedBindingDto = JsonConvert.SerializeObject(convertedBindingDtoFromLegacy); - var deserializedBindingDto = JsonConvert.DeserializeObject(serializedBindingDto); + var convertedBindingJsonFromLegacy = bindingJsonModelConverter.ConvertToModel(boundSonarCloudServerProject); + var serializedBindingModel = JsonConvert.SerializeObject(convertedBindingJsonFromLegacy); + var deserializedBindingModel = JsonConvert.DeserializeObject(serializedBindingModel); - var legacyBinding = bindingDtoConverter.ConvertFromDtoToLegacy(deserializedBindingDto, null); + var legacyBinding = bindingJsonModelConverter.ConvertFromModelToLegacy(deserializedBindingModel, null); legacyBinding.Should().BeEquivalentTo(boundSonarQubeProject, options => options.Excluding(x => x.ProjectName).Excluding(x => x.ServerUri).Excluding(x => x.Organization.Name)); legacyBinding.ServerUri.Should().BeEquivalentTo(boundSonarCloudServerProject.ServerConnection.ServerUri); @@ -190,13 +190,13 @@ public void CurrentSonarCloud_ToDto_ToJson_ToDto_ToLegacy_IsCorrect() } [TestMethod] - public void CurrentSonarQube_ToDto_ToJson_ToDto_ToLegacy_IsCorrect() + public void CurrentSonarQube_ToJsonModel_ToJson_ToJsonModel_ToLegacy_IsCorrect() { - var convertedBindingDtoFromLegacy = bindingDtoConverter.ConvertToDto(boundSonarQubeServerProject); - var serializedBindingDto = JsonConvert.SerializeObject(convertedBindingDtoFromLegacy); - var deserializedBindingDto = JsonConvert.DeserializeObject(serializedBindingDto); + var convertedBindingJsonFromLegacy = bindingJsonModelConverter.ConvertToModel(boundSonarQubeServerProject); + var serializedBindingModel = JsonConvert.SerializeObject(convertedBindingJsonFromLegacy); + var deserializedBindingModel = JsonConvert.DeserializeObject(serializedBindingModel); - var legacyBinding = bindingDtoConverter.ConvertFromDtoToLegacy(deserializedBindingDto, null); + var legacyBinding = bindingJsonModelConverter.ConvertFromModelToLegacy(deserializedBindingModel, null); legacyBinding.Should().BeEquivalentTo(boundSonarQubeProject, options => options.Excluding(x => x.ProjectName).Excluding(x => x.Organization)); legacyBinding.ProjectName.Should().BeNull(); @@ -204,27 +204,27 @@ public void CurrentSonarQube_ToDto_ToJson_ToDto_ToLegacy_IsCorrect() } [TestMethod] - public void CurrentSonarCloud_ToDto_ToJson_ToDto_ToCurrent_IsCorrect() + public void CurrentSonarCloud_ToJsonModel_ToJson_ToJsonModel_ToCurrent_IsCorrect() { - var convertedBindingDtoFromLegacy = bindingDtoConverter.ConvertToDto(boundSonarCloudServerProject); - var serializedBindingDto = JsonConvert.SerializeObject(convertedBindingDtoFromLegacy); - var deserializedBindingDto = JsonConvert.DeserializeObject(serializedBindingDto); - deserializedBindingDto.ServerConnectionId.Should().BeEquivalentTo(boundSonarCloudServerProject.ServerConnection.Id); + var convertedBindingJsonFromLegacy = bindingJsonModelConverter.ConvertToModel(boundSonarCloudServerProject); + var serializedBindingModel = JsonConvert.SerializeObject(convertedBindingJsonFromLegacy); + var deserializedBindingModel = JsonConvert.DeserializeObject(serializedBindingModel); + deserializedBindingModel.ServerConnectionId.Should().BeEquivalentTo(boundSonarCloudServerProject.ServerConnection.Id); - var binding = bindingDtoConverter.ConvertFromDto(deserializedBindingDto, boundSonarCloudServerProject.ServerConnection, "solution123"); + var binding = bindingJsonModelConverter.ConvertFromModel(deserializedBindingModel, boundSonarCloudServerProject.ServerConnection, "solution123"); binding.Should().BeEquivalentTo(boundSonarCloudServerProject); } [TestMethod] - public void CurrentSonarQube_ToDto_ToJson_ToDto_ToCurrent_IsCorrect() + public void CurrentSonarQube_ToJsonModel_ToJson_ToJsonModel_ToCurrent_IsCorrect() { - var convertedBindingDtoFromLegacy = bindingDtoConverter.ConvertToDto(boundSonarQubeServerProject); - var serializedBindingDto = JsonConvert.SerializeObject(convertedBindingDtoFromLegacy); - var deserializedBindingDto = JsonConvert.DeserializeObject(serializedBindingDto); - deserializedBindingDto.ServerConnectionId.Should().BeEquivalentTo(boundSonarQubeServerProject.ServerConnection.Id); + var convertedBindingJsonFromLegacy = bindingJsonModelConverter.ConvertToModel(boundSonarQubeServerProject); + var serializedBindingModel = JsonConvert.SerializeObject(convertedBindingJsonFromLegacy); + var deserializedBindingModel = JsonConvert.DeserializeObject(serializedBindingModel); + deserializedBindingModel.ServerConnectionId.Should().BeEquivalentTo(boundSonarQubeServerProject.ServerConnection.Id); - var binding = bindingDtoConverter.ConvertFromDto(deserializedBindingDto, boundSonarQubeServerProject.ServerConnection, "solution123"); + var binding = bindingJsonModelConverter.ConvertFromModel(deserializedBindingModel, boundSonarQubeServerProject.ServerConnection, "solution123"); binding.Should().BeEquivalentTo(boundSonarQubeServerProject); } diff --git a/src/ConnectedMode.UnitTests/Persistence/BoundSonarQubeProjectTests.cs b/src/ConnectedMode.UnitTests/Persistence/BoundSonarQubeProjectTests.cs index 378e34220..1318f7cdd 100644 --- a/src/ConnectedMode.UnitTests/Persistence/BoundSonarQubeProjectTests.cs +++ b/src/ConnectedMode.UnitTests/Persistence/BoundSonarQubeProjectTests.cs @@ -50,7 +50,7 @@ public void BoundProject_Serialization() } [TestMethod] - public void BoundProject_BindingDto_Serialization() + public void BoundProject_BindingJsonModel_Serialization() { // Arrange var serverUri = new Uri("https://finding-nemo.org"); @@ -59,7 +59,7 @@ public void BoundProject_BindingDto_Serialization() // Act (serialize + de-serialize) string data = JsonHelper.Serialize(testSubject); - BindingDto deserialized = JsonHelper.Deserialize(data); + BindingJsonModel deserialized = JsonHelper.Deserialize(data); // Assert deserialized.Should().NotBe(testSubject); diff --git a/src/ConnectedMode.UnitTests/Persistence/ServerConnectionsRepositoryTests.cs b/src/ConnectedMode.UnitTests/Persistence/ServerConnectionsRepositoryTests.cs index bc214603e..03e2e2a20 100644 --- a/src/ConnectedMode.UnitTests/Persistence/ServerConnectionsRepositoryTests.cs +++ b/src/ConnectedMode.UnitTests/Persistence/ServerConnectionsRepositoryTests.cs @@ -18,6 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +using System.ComponentModel; using System.IO; using System.IO.Abstractions; using SonarLint.VisualStudio.ConnectedMode.Binding; @@ -338,6 +339,32 @@ public void TryAdd_WritingThrowsException_DoesNotUpdateConnectionAndWritesLog() logger.Received(1).WriteLine($"Failed updating the {ServerConnectionsRepository.ConnectionsFileName}: {exceptionMsg}"); } + [TestMethod] + public void TryAdd_DoesNotAddConnection_DoesNotInvokeConnectionChangedEvent() + { + MockReadingFile(new ServerConnectionsListJsonModel()); + jsonFileHandler.TryWriteToFile(Arg.Any(), Arg.Any()).Returns(false); + var eventHandler = Substitute.For(); + testSubject.ConnectionChanged += eventHandler; + + testSubject.TryAdd(sonarCloudServerConnection); + + eventHandler.DidNotReceive().Invoke(testSubject, Arg.Any()); + } + + [TestMethod] + public void TryAdd_AddsConnection_InvokesConnectionChangedEvent() + { + MockReadingFile(new ServerConnectionsListJsonModel()); + jsonFileHandler.TryWriteToFile(Arg.Any(), Arg.Any()).Returns(true); + var eventHandler = Substitute.For(); + testSubject.ConnectionChanged += eventHandler; + + testSubject.TryAdd(sonarCloudServerConnection); + + eventHandler.Received().Invoke(testSubject, Arg.Any()); + } + [TestMethod] public void TryDelete_FileCouldNotBeRead_ReturnsFalse() { @@ -439,6 +466,32 @@ public void TryDelete_WritingThrowsException_DoesNotUpdateConnectionAndWritesLog logger.Received(1).WriteLine($"Failed updating the {ServerConnectionsRepository.ConnectionsFileName}: {exceptionMsg}"); } + [TestMethod] + public void TryDelete_DoesNotDeleteConnection_DoesNotInvokeConnectionChangedEvent() + { + var sonarQube = MockFileWithOneSonarQubeConnection(); + jsonFileHandler.TryWriteToFile(Arg.Any(), Arg.Any()).Returns(false); + var eventHandler = Substitute.For(); + testSubject.ConnectionChanged += eventHandler; + + testSubject.TryDelete(sonarQube.Id); + + eventHandler.DidNotReceive().Invoke(testSubject, Arg.Any()); + } + + [TestMethod] + public void TryDelete_DeletesConnection_InvokesConnectionChangedEvent() + { + var sonarQube = MockFileWithOneSonarQubeConnection(); + jsonFileHandler.TryWriteToFile(Arg.Any(), Arg.Any()).Returns(true); + var eventHandler = Substitute.For(); + testSubject.ConnectionChanged += eventHandler; + + testSubject.TryDelete(sonarQube.Id); + + eventHandler.Received(1).Invoke(testSubject, Arg.Any()); + } + [TestMethod] public void TryUpdateSettingsById_FileCouldNotBeRead_ReturnsFalse() { @@ -505,6 +558,32 @@ public void TryUpdateSettingsById_WritingThrowsException_DoesNotUpdateConnection logger.Received(1).WriteLine($"Failed updating the {ServerConnectionsRepository.ConnectionsFileName}: {exceptionMsg}"); } + [TestMethod] + public void TryUpdateSettingsById_DoesNotUpdateConnection_DoesNotInvokeConnectionChangedEvent() + { + var sonarQube = MockFileWithOneSonarQubeConnection(); + jsonFileHandler.TryWriteToFile(Arg.Any(), Arg.Any()).Returns(false); + var eventHandler = Substitute.For(); + testSubject.ConnectionChanged += eventHandler; + + testSubject.TryDelete(sonarQube.Id); + + eventHandler.DidNotReceive().Invoke(testSubject, Arg.Any()); + } + + [TestMethod] + public void TryUpdateSettingsById_UpdatesConnection_InvokesConnectionChangedEvent() + { + var sonarQube = MockFileWithOneSonarQubeConnection(); + jsonFileHandler.TryWriteToFile(Arg.Any(), Arg.Any()).Returns(true); + var eventHandler = Substitute.For(); + testSubject.ConnectionChanged += eventHandler; + + testSubject.TryUpdateSettingsById(sonarQube.Id, new ServerConnectionSettings(true)); + + eventHandler.Received(1).Invoke(testSubject, Arg.Any()); + } + [TestMethod] public void TryUpdateCredentialsById_ConnectionDoesNotExist_DoesNotUpdateCredentials() { @@ -540,6 +619,30 @@ public void TryUpdateCredentialsById_SonarQubeConnectionExists_UpdatesCredential credentialsLoader.Received(1).Save(newCredentials, sonarQube.ServerUri); } + [TestMethod] + public void TryUpdateCredentialsById_DoesNotUpdateCredentials_DoesNotInvokeConnectionChangedEvent() + { + MockReadingFile(new ServerConnectionsListJsonModel()); + var eventHandler = Substitute.For>(); + testSubject.CredentialsChanged += eventHandler; + + testSubject.TryUpdateCredentialsById("non-existingConn", Substitute.For()); + + eventHandler.DidNotReceive().Invoke(testSubject, Arg.Any()); + } + + [TestMethod] + public void TryUpdateCredentialsById_UpdatesCredentials_InvokesConnectionChangedEvent() + { + var sonarQube = MockFileWithOneSonarQubeConnection(); + var eventHandler = Substitute.For>(); + testSubject.CredentialsChanged += eventHandler; + + testSubject.TryUpdateCredentialsById(sonarQube.Id, Substitute.For()); + + eventHandler.Received(1).Invoke(testSubject, Arg.Is(args => args.ServerConnection == sonarQube)); + } + [TestMethod] [DataRow(true)] [DataRow(false)] diff --git a/src/ConnectedMode.UnitTests/Persistence/SolutionBindingFileLoaderTests.cs b/src/ConnectedMode.UnitTests/Persistence/SolutionBindingFileLoaderTests.cs index 12625f989..5912c344e 100644 --- a/src/ConnectedMode.UnitTests/Persistence/SolutionBindingFileLoaderTests.cs +++ b/src/ConnectedMode.UnitTests/Persistence/SolutionBindingFileLoaderTests.cs @@ -32,7 +32,7 @@ public class SolutionBindingFileLoaderTests private Mock logger; private Mock fileSystem; private SolutionBindingFileLoader testSubject; - private BindingDto bindingDto; + private BindingJsonModel bindingJsonModel; private string serializedProject; private const string MockFilePath = "c:\\test.txt"; @@ -48,7 +48,7 @@ public void TestInitialize() fileSystem.Setup(x => x.Directory.Exists(MockDirectory)).Returns(true); - bindingDto = new BindingDto + bindingJsonModel = new BindingJsonModel { ServerUri = new Uri("http://xxx.www.zzz/yyy:9000"), Organization = null, @@ -101,7 +101,7 @@ public void Save_DirectoryDoesNotExist_DirectoryIsCreated() { fileSystem.Setup(x => x.Directory.Exists(MockDirectory)).Returns(false); - testSubject.Save(MockFilePath, bindingDto); + testSubject.Save(MockFilePath, bindingJsonModel); fileSystem.Verify(x => x.Directory.CreateDirectory(MockDirectory), Times.Once); } @@ -111,7 +111,7 @@ public void Save_DirectoryExists_DirectoryNotCreated() { fileSystem.Setup(x => x.Directory.Exists(MockDirectory)).Returns(true); - testSubject.Save(MockFilePath, bindingDto); + testSubject.Save(MockFilePath, bindingJsonModel); fileSystem.Verify(x => x.Directory.CreateDirectory(It.IsAny()), Times.Never); } @@ -121,7 +121,7 @@ public void Save_ReturnsTrue() { fileSystem.Setup(x => x.File.WriteAllText(MockFilePath, serializedProject)); - var actual = testSubject.Save(MockFilePath, bindingDto); + var actual = testSubject.Save(MockFilePath, bindingJsonModel); actual.Should().BeTrue(); } @@ -130,7 +130,7 @@ public void Save_FileSerializedAndWritten() { fileSystem.Setup(x => x.File.WriteAllText(MockFilePath, serializedProject)); - testSubject.Save(MockFilePath, bindingDto); + testSubject.Save(MockFilePath, bindingJsonModel); fileSystem.Verify(x => x.File.WriteAllText(MockFilePath, serializedProject), Times.Once); } @@ -140,7 +140,7 @@ public void Save_NonCriticalException_False() { fileSystem.Setup(x => x.File.WriteAllText(MockFilePath, It.IsAny())).Throws(); - var actual = testSubject.Save(MockFilePath, bindingDto); + var actual = testSubject.Save(MockFilePath, bindingJsonModel); actual.Should().BeFalse(); } @@ -149,7 +149,7 @@ public void Save_CriticalException_Exception() { fileSystem.Setup(x => x.File.WriteAllText(MockFilePath, It.IsAny())).Throws(); - Action act = () => testSubject.Save(MockFilePath, bindingDto); + Action act = () => testSubject.Save(MockFilePath, bindingJsonModel); act.Should().ThrowExactly(); } @@ -210,7 +210,7 @@ public void Load_FileExists_DeserializedProject() fileSystem.Setup(x => x.File.ReadAllText(MockFilePath)).Returns(serializedProject); var actual = testSubject.Load(MockFilePath); - actual.Should().BeEquivalentTo(bindingDto); + actual.Should().BeEquivalentTo(bindingJsonModel); } [TestMethod] @@ -224,7 +224,7 @@ public void Load_FileExists_ProjectWithNonUtcTimestamp_DeserializedProjectWithCo fileSystem.Setup(x => x.File.ReadAllText(MockFilePath)).Returns(serializedProject); var actual = testSubject.Load(MockFilePath); - actual.Should().BeEquivalentTo(bindingDto); + actual.Should().BeEquivalentTo(bindingJsonModel); var deserializedTimestamp = actual.Profiles[Language.CSharp].ProfileTimestamp.Value.ToUniversalTime(); deserializedTimestamp.Should().Be(new DateTime(2020, 2, 25, 8, 57, 54)); diff --git a/src/ConnectedMode.UnitTests/Persistence/SolutionBindingRepositoryTests.cs b/src/ConnectedMode.UnitTests/Persistence/SolutionBindingRepositoryTests.cs index 0e4fc3891..68a46629b 100644 --- a/src/ConnectedMode.UnitTests/Persistence/SolutionBindingRepositoryTests.cs +++ b/src/ConnectedMode.UnitTests/Persistence/SolutionBindingRepositoryTests.cs @@ -31,13 +31,13 @@ namespace SonarLint.VisualStudio.ConnectedMode.UnitTests.Persistence; public class SolutionBindingRepositoryTests { private IUnintrusiveBindingPathProvider unintrusiveBindingPathProvider; - private IBindingDtoConverter bindingDtoConverter; + private IBindingJsonModelConverter bindingJsonModelConverter; private IServerConnectionsRepository serverConnectionsRepository; private ISolutionBindingCredentialsLoader credentialsLoader; private ISolutionBindingFileLoader solutionBindingFileLoader; private TestLogger logger; - private BindingDto bindingDto; + private BindingJsonModel bindingJsonModel; private ServerConnection serverConnection; private BoundServerProject boundServerProject; private ISolutionBindingRepository testSubject; @@ -49,19 +49,19 @@ public class SolutionBindingRepositoryTests public void TestInitialize() { unintrusiveBindingPathProvider = Substitute.For(); - bindingDtoConverter = Substitute.For(); + bindingJsonModelConverter = Substitute.For(); serverConnectionsRepository = Substitute.For(); credentialsLoader = Substitute.For(); solutionBindingFileLoader = Substitute.For(); logger = new TestLogger(); - testSubject = new SolutionBindingRepository(unintrusiveBindingPathProvider, bindingDtoConverter, serverConnectionsRepository, solutionBindingFileLoader, credentialsLoader, logger); + testSubject = new SolutionBindingRepository(unintrusiveBindingPathProvider, bindingJsonModelConverter, serverConnectionsRepository, solutionBindingFileLoader, credentialsLoader, logger); mockCredentials = new BasicAuthCredentials("user", "pwd".ToSecureString()); serverConnection = new ServerConnection.SonarCloud("org"); boundServerProject = new BoundServerProject("solution.123", "project_123", serverConnection); - bindingDto = new BindingDto + bindingJsonModel = new BindingJsonModel { ServerConnectionId = serverConnection.Id }; @@ -72,13 +72,13 @@ public void MefCtor_CheckIsExported() { MefTestHelpers.CheckTypeCanBeImported( MefTestHelpers.CreateExport(), - MefTestHelpers.CreateExport(), + MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport()); MefTestHelpers.CheckTypeCanBeImported( MefTestHelpers.CreateExport(), - MefTestHelpers.CreateExport(), + MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport()); @@ -93,7 +93,7 @@ public void MefCtor_CheckIsSingleton() [TestMethod] public void Read_ProjectIsNull_Null() { - solutionBindingFileLoader.Load(MockFilePath).Returns(null as BindingDto); + solutionBindingFileLoader.Load(MockFilePath).Returns(null as BindingJsonModel); var actual = testSubject.Read(MockFilePath); actual.Should().Be(null); @@ -102,7 +102,7 @@ public void Read_ProjectIsNull_Null() [TestMethod] public void Read_ProjectIsNull_CredentialsNotRead() { - solutionBindingFileLoader.Load(MockFilePath).Returns(null as BindingDto); + solutionBindingFileLoader.Load(MockFilePath).Returns(null as BindingJsonModel); testSubject.Read(MockFilePath); @@ -112,14 +112,14 @@ public void Read_ProjectIsNull_CredentialsNotRead() [TestMethod] public void Read_ProjectIsNotNull_ReadsConnectionRepositoryForConnection() { - serverConnectionsRepository.TryGet(bindingDto.ServerConnectionId, out Arg.Any()).Returns(call => + serverConnectionsRepository.TryGet(bindingJsonModel.ServerConnectionId, out Arg.Any()).Returns(call => { call[1] = serverConnection; return true; }); - solutionBindingFileLoader.Load(MockFilePath).Returns(bindingDto); + solutionBindingFileLoader.Load(MockFilePath).Returns(bindingJsonModel); unintrusiveBindingPathProvider.GetBindingKeyFromPath(MockFilePath).Returns(boundServerProject.LocalBindingKey); - bindingDtoConverter.ConvertFromDto(bindingDto, serverConnection, boundServerProject.LocalBindingKey).Returns(boundServerProject); + bindingJsonModelConverter.ConvertFromModel(bindingJsonModel, serverConnection, boundServerProject.LocalBindingKey).Returns(boundServerProject); var actual = testSubject.Read(MockFilePath); @@ -131,12 +131,12 @@ public void Read_ProjectIsNotNull_ReadsConnectionRepositoryForConnection() [TestMethod] public void Read_ProjectIsNotNull_NoConnection_ReturnsNull() { - serverConnectionsRepository.TryGet(bindingDto.ServerConnectionId, out Arg.Any()).Returns(call => + serverConnectionsRepository.TryGet(bindingJsonModel.ServerConnectionId, out Arg.Any()).Returns(call => { call[1] = null; return false; }); - solutionBindingFileLoader.Load(MockFilePath).Returns(bindingDto); + solutionBindingFileLoader.Load(MockFilePath).Returns(bindingJsonModel); var actual = testSubject.Read(MockFilePath); @@ -184,8 +184,8 @@ public void Write_EventTriggered_DependingOnFileWriteStatus(bool triggered) { var eventHandler = Substitute.For(); testSubject.BindingUpdated += eventHandler; - bindingDtoConverter.ConvertToDto(boundServerProject).Returns(bindingDto); - solutionBindingFileLoader.Save(MockFilePath, bindingDto).Returns(triggered); + bindingJsonModelConverter.ConvertToModel(boundServerProject).Returns(bindingJsonModel); + solutionBindingFileLoader.Save(MockFilePath, bindingJsonModel).Returns(triggered); testSubject.Write(MockFilePath, boundServerProject); @@ -196,8 +196,8 @@ public void Write_EventTriggered_DependingOnFileWriteStatus(bool triggered) [TestMethod] public void Write_FileWritten_NoOnSaveCallback_NoException() { - bindingDtoConverter.ConvertToDto(boundServerProject).Returns(bindingDto); - solutionBindingFileLoader.Save(MockFilePath, bindingDto).Returns(true); + bindingJsonModelConverter.ConvertToModel(boundServerProject).Returns(bindingJsonModel); + solutionBindingFileLoader.Save(MockFilePath, bindingJsonModel).Returns(true); Action act = () => testSubject.Write(MockFilePath, boundServerProject); act.Should().NotThrow(); @@ -252,7 +252,7 @@ public void List_SkipsBindingsThatCannotBeRead() SetUpUnintrusiveBindingPathProvider(bindingConfig1, bindingConfig2); SetUpConnections(connection1, connection2); var boundServerProject1 = SetUpBinding(solution1, connection1, bindingConfig1); - solutionBindingFileLoader.Load(bindingConfig2).Returns((BindingDto)null); + solutionBindingFileLoader.Load(bindingConfig2).Returns((BindingJsonModel)null); var result = testSubject.List(); @@ -272,7 +272,7 @@ public void List_CannotGetConnections_EmptyList() [TestMethod] public void LegacyRead_NoFile_ReturnsNull() { - solutionBindingFileLoader.Load(MockFilePath).Returns((BindingDto)null); + solutionBindingFileLoader.Load(MockFilePath).Returns((BindingJsonModel)null); ((ILegacySolutionBindingRepository)testSubject).Read(MockFilePath).Should().BeNull(); credentialsLoader.DidNotReceiveWithAnyArgs().Load(default); @@ -282,18 +282,18 @@ public void LegacyRead_NoFile_ReturnsNull() public void LegacyRead_ValidBinding_LoadsCredentials() { var boundSonarQubeProject = new BoundSonarQubeProject(); - bindingDto.ServerUri = new Uri("http://localhost/"); - credentialsLoader.Load(bindingDto.ServerUri).Returns(mockCredentials); - solutionBindingFileLoader.Load(MockFilePath).Returns(bindingDto); - bindingDtoConverter.ConvertFromDtoToLegacy(bindingDto, mockCredentials).Returns(boundSonarQubeProject); + bindingJsonModel.ServerUri = new Uri("http://localhost/"); + credentialsLoader.Load(bindingJsonModel.ServerUri).Returns(mockCredentials); + solutionBindingFileLoader.Load(MockFilePath).Returns(bindingJsonModel); + bindingJsonModelConverter.ConvertFromModelToLegacy(bindingJsonModel, mockCredentials).Returns(boundSonarQubeProject); ((ILegacySolutionBindingRepository)testSubject).Read(MockFilePath).Should().BeSameAs(boundSonarQubeProject); - credentialsLoader.Received().Load(bindingDto.ServerUri); + credentialsLoader.Received().Load(bindingJsonModel.ServerUri); } private BoundServerProject SetUpBinding(string solution, ServerConnection connection, string bindingConfig) { - var dto = new BindingDto{ServerConnectionId = connection?.Id}; + var dto = new BindingJsonModel{ServerConnectionId = connection?.Id}; solutionBindingFileLoader.Load(bindingConfig).Returns(dto); if (connection == null) { @@ -301,7 +301,7 @@ private BoundServerProject SetUpBinding(string solution, ServerConnection connec } var bound = new BoundServerProject(solution, "any", connection); unintrusiveBindingPathProvider.GetBindingKeyFromPath(bindingConfig).Returns(solution); - bindingDtoConverter.ConvertFromDto(dto, connection, solution).Returns(bound); + bindingJsonModelConverter.ConvertFromModel(dto, connection, solution).Returns(bound); return bound; } diff --git a/src/ConnectedMode/Persistence/BindingDto.cs b/src/ConnectedMode/Persistence/BindingJsonModel.cs similarity index 98% rename from src/ConnectedMode/Persistence/BindingDto.cs rename to src/ConnectedMode/Persistence/BindingJsonModel.cs index 579eaf43c..33ba8d86f 100644 --- a/src/ConnectedMode/Persistence/BindingDto.cs +++ b/src/ConnectedMode/Persistence/BindingJsonModel.cs @@ -29,7 +29,7 @@ namespace SonarLint.VisualStudio.ConnectedMode.Persistence; /// The information for the connection related properties are now stored in a separate file, but they are needed here for backward compatibility with previous binding formats /// [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] -internal class BindingDto +internal class BindingJsonModel { public string ServerConnectionId { get; set; } public Uri ServerUri { get; set; } // left here for backward compatibility reasons diff --git a/src/ConnectedMode/Persistence/BindingDtoConverter.cs b/src/ConnectedMode/Persistence/BindingJsonModelConverter.cs similarity index 59% rename from src/ConnectedMode/Persistence/BindingDtoConverter.cs rename to src/ConnectedMode/Persistence/BindingJsonModelConverter.cs index 5f50f3296..763724a04 100644 --- a/src/ConnectedMode/Persistence/BindingDtoConverter.cs +++ b/src/ConnectedMode/Persistence/BindingJsonModelConverter.cs @@ -24,24 +24,24 @@ namespace SonarLint.VisualStudio.ConnectedMode.Persistence; -internal interface IBindingDtoConverter +internal interface IBindingJsonModelConverter { - BoundServerProject ConvertFromDto(BindingDto bindingDto, ServerConnection connection, string localBindingKey); - BindingDto ConvertToDto(BoundServerProject binding); - BoundSonarQubeProject ConvertFromDtoToLegacy(BindingDto bindingDto, ICredentials credentials); + BoundServerProject ConvertFromModel(BindingJsonModel bindingJsonModel, ServerConnection connection, string localBindingKey); + BindingJsonModel ConvertToModel(BoundServerProject binding); + BoundSonarQubeProject ConvertFromModelToLegacy(BindingJsonModel bindingJsonModel, ICredentials credentials); } -[Export(typeof(IBindingDtoConverter))] +[Export(typeof(IBindingJsonModelConverter))] [PartCreationPolicy(CreationPolicy.Shared)] -internal class BindingDtoConverter : IBindingDtoConverter +internal class BindingJsonModelConverter : IBindingJsonModelConverter { - public BoundServerProject ConvertFromDto(BindingDto bindingDto, ServerConnection connection, string localBindingKey) => - new(localBindingKey, bindingDto.ProjectKey, connection) + public BoundServerProject ConvertFromModel(BindingJsonModel bindingJsonModel, ServerConnection connection, string localBindingKey) => + new(localBindingKey, bindingJsonModel.ProjectKey, connection) { - Profiles = bindingDto.Profiles + Profiles = bindingJsonModel.Profiles }; - public BindingDto ConvertToDto(BoundServerProject binding) => + public BindingJsonModel ConvertToModel(BoundServerProject binding) => new() { ProjectKey = binding.ServerProjectKey, @@ -54,13 +54,13 @@ public BindingDto ConvertToDto(BoundServerProject binding) => : null }; - public BoundSonarQubeProject ConvertFromDtoToLegacy(BindingDto bindingDto, ICredentials credentials) => - new(bindingDto.ServerUri, - bindingDto.ProjectKey, - bindingDto.ProjectName, + public BoundSonarQubeProject ConvertFromModelToLegacy(BindingJsonModel bindingJsonModel, ICredentials credentials) => + new(bindingJsonModel.ServerUri, + bindingJsonModel.ProjectKey, + bindingJsonModel.ProjectName, credentials, - bindingDto.Organization) + bindingJsonModel.Organization) { - Profiles = bindingDto.Profiles + Profiles = bindingJsonModel.Profiles }; } diff --git a/src/ConnectedMode/Persistence/ISolutionBindingFileLoader.cs b/src/ConnectedMode/Persistence/ISolutionBindingFileLoader.cs index a465c678f..69e70a2ea 100644 --- a/src/ConnectedMode/Persistence/ISolutionBindingFileLoader.cs +++ b/src/ConnectedMode/Persistence/ISolutionBindingFileLoader.cs @@ -22,7 +22,7 @@ namespace SonarLint.VisualStudio.ConnectedMode.Persistence { internal interface ISolutionBindingFileLoader { - BindingDto Load(string filePath); - bool Save(string filePath, BindingDto project); + BindingJsonModel Load(string filePath); + bool Save(string filePath, BindingJsonModel project); } } diff --git a/src/ConnectedMode/Persistence/ServerConnectionsRepository.cs b/src/ConnectedMode/Persistence/ServerConnectionsRepository.cs index 3578bc375..7554307cf 100644 --- a/src/ConnectedMode/Persistence/ServerConnectionsRepository.cs +++ b/src/ConnectedMode/Persistence/ServerConnectionsRepository.cs @@ -43,6 +43,9 @@ internal class ServerConnectionsRepository : IServerConnectionsRepository private readonly string connectionsStorageFilePath; private static readonly object LockObject = new(); + public event EventHandler ConnectionChanged; + public event EventHandler CredentialsChanged; + [ImportingConstructor] public ServerConnectionsRepository( IJsonFileHandler jsonFileHandle, @@ -127,6 +130,7 @@ public bool TryUpdateCredentialsById(string connectionId, ICredentials credentia if (wasFound) { credentialsLoader.Save(credentials, serverConnection.CredentialsUri); + OnCredentialsChanged(serverConnection); return true; } } @@ -229,7 +233,12 @@ private bool SafeUpdateConnectionsFile(Func, bool> tryUpd if (tryUpdateConnectionModels(serverConnections)) { var model = serverConnectionModelMapper.GetServerConnectionsListJsonModel(serverConnections); - return jsonFileHandle.TryWriteToFile(connectionsStorageFilePath, model); + var wasSaved = jsonFileHandle.TryWriteToFile(connectionsStorageFilePath, model); + if (wasSaved) + { + OnConnectionChanged(); + } + return wasSaved; } } catch (Exception ex) when (!ErrorHandler.IsCriticalException(ex)) @@ -240,4 +249,7 @@ private bool SafeUpdateConnectionsFile(Func, bool> tryUpd return false; } } + + private void OnConnectionChanged() => ConnectionChanged?.Invoke(this, EventArgs.Empty); + private void OnCredentialsChanged(ServerConnection serverConnection) => CredentialsChanged?.Invoke(this, new ServerConnectionUpdatedEventArgs(serverConnection)); } diff --git a/src/ConnectedMode/Persistence/SolutionBindingFileLoader.cs b/src/ConnectedMode/Persistence/SolutionBindingFileLoader.cs index 40859a7be..98953b5a0 100644 --- a/src/ConnectedMode/Persistence/SolutionBindingFileLoader.cs +++ b/src/ConnectedMode/Persistence/SolutionBindingFileLoader.cs @@ -44,7 +44,7 @@ internal SolutionBindingFileLoader(ILogger logger, IFileSystem fileSystem) this.fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); } - public bool Save(string filePath, BindingDto project) + public bool Save(string filePath, BindingJsonModel project) { var serializedProject = Serialize(project); @@ -65,7 +65,7 @@ private void WriteConfig(string configFile, string serializedProject) fileSystem.File.WriteAllText(configFile, serializedProject); } - public BindingDto Load(string filePath) + public BindingJsonModel Load(string filePath) { if (string.IsNullOrEmpty(filePath) || !fileSystem.File.Exists(filePath)) { @@ -110,9 +110,9 @@ private bool SafePerformFileSystemOperation(Action operation) } } - private BindingDto Deserialize(string projectJson) + private BindingJsonModel Deserialize(string projectJson) { - return JsonConvert.DeserializeObject(projectJson, new JsonSerializerSettings + return JsonConvert.DeserializeObject(projectJson, new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.IsoDateFormat, DateTimeZoneHandling = DateTimeZoneHandling.Local, @@ -120,7 +120,7 @@ private BindingDto Deserialize(string projectJson) }); } - private string Serialize(BindingDto project) + private string Serialize(BindingJsonModel project) { return JsonConvert.SerializeObject(project, Formatting.Indented, new JsonSerializerSettings { diff --git a/src/ConnectedMode/Persistence/SolutionBindingRepository.cs b/src/ConnectedMode/Persistence/SolutionBindingRepository.cs index 008272c40..bdeea600e 100644 --- a/src/ConnectedMode/Persistence/SolutionBindingRepository.cs +++ b/src/ConnectedMode/Persistence/SolutionBindingRepository.cs @@ -35,17 +35,17 @@ internal class SolutionBindingRepository : ISolutionBindingRepository, ILegacySo private readonly ISolutionBindingCredentialsLoader credentialsLoader; private readonly IUnintrusiveBindingPathProvider unintrusiveBindingPathProvider; private readonly IServerConnectionsRepository serverConnectionsRepository; - private readonly IBindingDtoConverter bindingDtoConverter; + private readonly IBindingJsonModelConverter bindingJsonModelConverter; private readonly ILogger logger; [ImportingConstructor] public SolutionBindingRepository(IUnintrusiveBindingPathProvider unintrusiveBindingPathProvider, - IBindingDtoConverter bindingDtoConverter, + IBindingJsonModelConverter bindingJsonModelConverter, IServerConnectionsRepository serverConnectionsRepository, ICredentialStoreService credentialStoreService, ILogger logger) : this(unintrusiveBindingPathProvider, - bindingDtoConverter, + bindingJsonModelConverter, serverConnectionsRepository, new SolutionBindingFileLoader(logger), new SolutionBindingCredentialsLoader(credentialStoreService), @@ -54,7 +54,7 @@ public SolutionBindingRepository(IUnintrusiveBindingPathProvider unintrusiveBind } internal /* for testing */ SolutionBindingRepository(IUnintrusiveBindingPathProvider unintrusiveBindingPathProvider, - IBindingDtoConverter bindingDtoConverter, + IBindingJsonModelConverter bindingJsonModelConverter, IServerConnectionsRepository serverConnectionsRepository, ISolutionBindingFileLoader solutionBindingFileLoader, ISolutionBindingCredentialsLoader credentialsLoader, @@ -62,7 +62,7 @@ public SolutionBindingRepository(IUnintrusiveBindingPathProvider unintrusiveBind { this.unintrusiveBindingPathProvider = unintrusiveBindingPathProvider; this.serverConnectionsRepository = serverConnectionsRepository; - this.bindingDtoConverter = bindingDtoConverter; + this.bindingJsonModelConverter = bindingJsonModelConverter; this.solutionBindingFileLoader = solutionBindingFileLoader ?? throw new ArgumentNullException(nameof(solutionBindingFileLoader)); this.credentialsLoader = credentialsLoader ?? throw new ArgumentNullException(nameof(credentialsLoader)); this.logger = logger; @@ -70,11 +70,11 @@ public SolutionBindingRepository(IUnintrusiveBindingPathProvider unintrusiveBind BoundSonarQubeProject ILegacySolutionBindingRepository.Read(string configFilePath) { - var bindingDto = ReadBindingFile(configFilePath); - return bindingDto switch + var bindingJsonModel = ReadBindingFile(configFilePath); + return bindingJsonModel switch { null => null, - not null => bindingDtoConverter.ConvertFromDtoToLegacy(bindingDto, credentialsLoader.Load(bindingDto.ServerUri)) + not null => bindingJsonModelConverter.ConvertFromModelToLegacy(bindingJsonModel, credentialsLoader.Load(bindingJsonModel.ServerUri)) }; } @@ -92,7 +92,7 @@ public bool Write(string configFilePath, BoundServerProject binding) return false; } - if (!solutionBindingFileLoader.Save(configFilePath, bindingDtoConverter.ConvertToDto(binding))) + if (!solutionBindingFileLoader.Save(configFilePath, bindingJsonModelConverter.ConvertToModel(binding))) { return false; } @@ -115,27 +115,27 @@ public IEnumerable List() foreach (var bindingConfigPath in bindingConfigPaths) { - var bindingDto = ReadBindingFile(bindingConfigPath); + var bindingJsonModel = ReadBindingFile(bindingConfigPath); - if (bindingDto == null) + if (bindingJsonModel == null) { logger.LogVerbose($"Skipped {bindingConfigPath} because it could not be read"); continue; } - if (connections.FirstOrDefault(c => c.Id == bindingDto.ServerConnectionId) is not {} serverConnection) + if (connections.FirstOrDefault(c => c.Id == bindingJsonModel.ServerConnectionId) is not {} serverConnection) { - logger.LogVerbose($"Skipped {bindingConfigPath} because connection {bindingDto.ServerConnectionId} doesn't exist"); + logger.LogVerbose($"Skipped {bindingConfigPath} because connection {bindingJsonModel.ServerConnectionId} doesn't exist"); continue; } - var boundServerProject = Convert(bindingDto, serverConnection, bindingConfigPath); + var boundServerProject = Convert(bindingJsonModel, serverConnection, bindingConfigPath); yield return boundServerProject; } } - private BindingDto ReadBindingFile(string configFilePath) + private BindingJsonModel ReadBindingFile(string configFilePath) { var bound = solutionBindingFileLoader.Load(configFilePath); @@ -151,11 +151,11 @@ private BindingDto ReadBindingFile(string configFilePath) } - private BoundServerProject Convert(BindingDto bindingDto, string configFilePath) => - bindingDto is not null && serverConnectionsRepository.TryGet(bindingDto.ServerConnectionId, out var connection) - ? Convert(bindingDto, connection, configFilePath) + private BoundServerProject Convert(BindingJsonModel bindingJsonModel, string configFilePath) => + bindingJsonModel is not null && serverConnectionsRepository.TryGet(bindingJsonModel.ServerConnectionId, out var connection) + ? Convert(bindingJsonModel, connection, configFilePath) : null; - private BoundServerProject Convert(BindingDto bindingDto, ServerConnection connection, string configFilePath) => - bindingDtoConverter.ConvertFromDto(bindingDto, connection, unintrusiveBindingPathProvider.GetBindingKeyFromPath(configFilePath)); + private BoundServerProject Convert(BindingJsonModel bindingJsonModel, ServerConnection connection, string configFilePath) => + bindingJsonModelConverter.ConvertFromModel(bindingJsonModel, connection, unintrusiveBindingPathProvider.GetBindingKeyFromPath(configFilePath)); } diff --git a/src/ConnectedMode/UI/DeleteConnection/PreventDeleteConnectionDialog.xaml b/src/ConnectedMode/UI/DeleteConnection/PreventDeleteConnectionDialog.xaml index 8287d870f..0aa7c83b6 100644 --- a/src/ConnectedMode/UI/DeleteConnection/PreventDeleteConnectionDialog.xaml +++ b/src/ConnectedMode/UI/DeleteConnection/PreventDeleteConnectionDialog.xaml @@ -4,6 +4,7 @@ xmlns:res="clr-namespace:SonarLint.VisualStudio.ConnectedMode.UI.Resources" xmlns:ui="clr-namespace:SonarLint.VisualStudio.ConnectedMode.UI" xmlns:converters="clr-namespace:SonarLint.VisualStudio.Core.WPF;assembly=SonarLint.VisualStudio.Core" + xmlns:links="clr-namespace:SonarLint.VisualStudio.Core;assembly=SonarLint.VisualStudio.Core" Title="{x:Static res:UiResources.DeleteConnectionDialogTitle}" Width="600" MinHeight="200" @@ -57,7 +58,7 @@ ItemsSource="{Binding ProjectsToUnbind}"> - here + here diff --git a/src/ConnectedMode/UI/ManageBinding/ManageBindingDialog.xaml b/src/ConnectedMode/UI/ManageBinding/ManageBindingDialog.xaml index 4e70f647c..6a0773237 100644 --- a/src/ConnectedMode/UI/ManageBinding/ManageBindingDialog.xaml +++ b/src/ConnectedMode/UI/ManageBinding/ManageBindingDialog.xaml @@ -5,8 +5,7 @@ xmlns:res="clr-namespace:SonarLint.VisualStudio.ConnectedMode.UI.Resources" xmlns:ui="clr-namespace:SonarLint.VisualStudio.ConnectedMode.UI" xmlns:wpf="clr-namespace:SonarLint.VisualStudio.Core.WPF;assembly=SonarLint.VisualStudio.Core" - xmlns:imaging="clr-namespace:Microsoft.VisualStudio.Imaging;assembly=Microsoft.VisualStudio.Imaging" - xmlns:vsimagecatalog="clr-namespace:Microsoft.VisualStudio.Imaging;assembly=Microsoft.VisualStudio.ImageCatalog" + xmlns:links="clr-namespace:SonarLint.VisualStudio.Core;assembly=SonarLint.VisualStudio.Core" Title="{x:Static res:UiResources.ManageBindingDialogTitle}" WindowStartupLocation="CenterOwner" Initialized="ManageBindingDialog_OnInitialized" @@ -55,20 +54,10 @@ - @@ -103,7 +92,7 @@