-
Notifications
You must be signed in to change notification settings - Fork 77
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SLVS-1304 Telemetry data migration to SLCore (#5572)
- Loading branch information
1 parent
ac1ee80
commit 21f2c4d
Showing
14 changed files
with
379 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* SonarLint for Visual Studio | ||
* Copyright (C) 2016-2024 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.Telemetry.Legacy; | ||
|
||
|
||
public interface ITelemetryDataRepository | ||
{ | ||
TelemetryData ReadTelemetryData(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/* | ||
* SonarLint for Visual Studio | ||
* Copyright (C) 2016-2024 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. | ||
*/ | ||
|
||
using System.ComponentModel; | ||
using System.Globalization; | ||
using System.Xml.Serialization; | ||
|
||
namespace SonarLint.VisualStudio.Core.Telemetry.Legacy; | ||
|
||
public sealed class TelemetryData | ||
{ | ||
public bool IsAnonymousDataShared { get; set; } | ||
|
||
public int NumberOfDaysOfUse { get; set; } | ||
|
||
[XmlIgnore] public DateTimeOffset InstallationDate { get; set; } | ||
|
||
[XmlElement(nameof(InstallationDate)), EditorBrowsable(EditorBrowsableState.Never)] | ||
public string InstallationDateString | ||
{ | ||
get => InstallationDate.ToString("o"); | ||
set => InstallationDate = ParseSavedString(value); | ||
} | ||
|
||
private static DateTimeOffset ParseSavedString(string data) | ||
{ | ||
// ParseExact will throw an exception when value is invalid date, but | ||
// XmlSerializer will swallow it and return default(TelemetryData) | ||
return DateTimeOffset.ParseExact(data, "o", CultureInfo.InvariantCulture, | ||
DateTimeStyles.AssumeLocal | DateTimeStyles.AdjustToUniversal); | ||
} | ||
} |
90 changes: 90 additions & 0 deletions
90
src/Integration.UnitTests/Telemetry/Legacy/TelemetryDataRepositoryTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
* SonarLint for Visual Studio | ||
* Copyright (C) 2016-2024 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. | ||
*/ | ||
|
||
using System.IO.Abstractions; | ||
using SonarLint.VisualStudio.Core; | ||
using SonarLint.VisualStudio.Core.Telemetry.Legacy; | ||
using SonarLint.VisualStudio.Integration.Telemetry.Legacy; | ||
|
||
namespace SonarLint.VisualStudio.Integration.UnitTests.Telemetry.Legacy; | ||
|
||
[TestClass] | ||
public class TelemetryDataRepositoryTests | ||
{ | ||
[TestMethod] | ||
public void Data_WhenTelemetryFileDoesNotExist_ReturnNull() | ||
{ | ||
var environmentVariableProvider = Substitute.For<IEnvironmentVariableProvider>(); | ||
var fileSystem = CreateFileSystem(environmentVariableProvider, false); | ||
var telemetryDataRepository = new TelemetryDataRepository(fileSystem, environmentVariableProvider); | ||
|
||
var actualData = telemetryDataRepository.ReadTelemetryData(); | ||
|
||
actualData.Should().BeNull(); | ||
} | ||
|
||
[TestMethod] | ||
public void Data_WhenTelemetryFileExist_ShouldProvideTelemetryData() | ||
{ | ||
const string fileContent = """ | ||
<?xml version="1.0" encoding="utf-16"?> | ||
<TelemetryData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
<IsAnonymousDataShared>false</IsAnonymousDataShared> | ||
<NumberOfDaysOfUse>10</NumberOfDaysOfUse> | ||
<InstallationDate>2010-03-15T06:15:42.1234567+01:00</InstallationDate> | ||
</TelemetryData> | ||
"""; | ||
var environmentVariableProvider = Substitute.For<IEnvironmentVariableProvider>(); | ||
var fileSystem = CreateFileSystem(environmentVariableProvider, true); | ||
fileSystem.File.ReadAllText(Arg.Any<string>()).Returns(fileContent); | ||
var telemetryDataRepository = new TelemetryDataRepository(fileSystem, environmentVariableProvider); | ||
|
||
var actualData = telemetryDataRepository.ReadTelemetryData(); | ||
|
||
var expectedData = new TelemetryData | ||
{ | ||
IsAnonymousDataShared = false, | ||
InstallationDateString = "2010-03-15T06:15:42.1234567+01:00", | ||
NumberOfDaysOfUse = 10 | ||
}; | ||
actualData.Should().BeEquivalentTo(expectedData); | ||
} | ||
|
||
[TestMethod] | ||
public void Data_WhenTelemetryFileIsCorrupted_ShouldDeleteFileAndReturnNull() | ||
{ | ||
var environmentVariableProvider = Substitute.For<IEnvironmentVariableProvider>(); | ||
var fileSystem = CreateFileSystem(environmentVariableProvider, true); | ||
var telemetryDataRepository = new TelemetryDataRepository(fileSystem, environmentVariableProvider); | ||
|
||
var actualData = telemetryDataRepository.ReadTelemetryData(); | ||
|
||
fileSystem.File.Received().Delete(Arg.Any<string>()); | ||
actualData.Should().BeNull(); | ||
} | ||
|
||
private static IFileSystem CreateFileSystem(IEnvironmentVariableProvider environmentVariableProvider, bool fileExists) | ||
{ | ||
var expectedFilePath = TelemetryDataRepository.GetStorageFilePath(environmentVariableProvider); | ||
var fileSystem = Substitute.For<IFileSystem>(); | ||
fileSystem.File.Exists(expectedFilePath).Returns(fileExists); | ||
return fileSystem; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
src/Integration/Telemetry/Legacy/TelemetryDataRepository.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
* SonarLint for Visual Studio | ||
* Copyright (C) 2016-2024 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. | ||
*/ | ||
|
||
using System.ComponentModel.Composition; | ||
using System.IO; | ||
using System.IO.Abstractions; | ||
using System.Xml.Serialization; | ||
using SonarLint.VisualStudio.Core; | ||
using SonarLint.VisualStudio.Core.Telemetry.Legacy; | ||
|
||
namespace SonarLint.VisualStudio.Integration.Telemetry.Legacy; | ||
|
||
[Export(typeof(ITelemetryDataRepository))] | ||
[PartCreationPolicy(CreationPolicy.Shared)] | ||
public sealed class TelemetryDataRepository : ITelemetryDataRepository | ||
{ | ||
private readonly string storageFilePath; | ||
private readonly XmlSerializer telemetrySerializer = new(typeof(TelemetryData)); | ||
private readonly IFileSystem fileSystem; | ||
|
||
public TelemetryDataRepository() : this(new FileSystem(), EnvironmentVariableProvider.Instance) | ||
{ | ||
} | ||
|
||
internal /* for testing */ TelemetryDataRepository(IFileSystem fileSystem, | ||
IEnvironmentVariableProvider environmentVariables) | ||
{ | ||
this.fileSystem = fileSystem; | ||
storageFilePath = GetStorageFilePath(environmentVariables); | ||
} | ||
|
||
public TelemetryData ReadTelemetryData() | ||
{ | ||
TelemetryData data = null; | ||
RetryHelper.RetryOnException(3, TimeSpan.FromSeconds(2), () => { data = ReadXmlFile(); }); | ||
return data; | ||
} | ||
|
||
private TelemetryData ReadXmlFile() | ||
{ | ||
if (!fileSystem.File.Exists(storageFilePath)) | ||
{ | ||
return null; | ||
} | ||
|
||
try | ||
{ | ||
var fileContent = fileSystem.File.ReadAllText(storageFilePath); | ||
return telemetrySerializer.Deserialize(new StringReader(fileContent)) as TelemetryData; | ||
} | ||
catch (InvalidOperationException) | ||
{ | ||
fileSystem.File.Delete(storageFilePath); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
internal static string GetStorageFilePath(IEnvironmentVariableProvider environmentVariables) | ||
{ | ||
// Note: the data is stored in the roaming profile, so it will be sync across machines for domain-joined users. | ||
var appDataFolder = environmentVariables.GetSLVSAppDataRootPath(); | ||
var filePath = Path.Combine(appDataFolder, "telemetry.xml"); | ||
return Path.GetFullPath(filePath); // get rid of the .. in file path | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 63 additions & 0 deletions
63
src/SLCore.UnitTests/Configuration/SlCoreTelemetryMigrationProviderTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* SonarLint for Visual Studio | ||
* Copyright (C) 2016-2024 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. | ||
*/ | ||
|
||
using SonarLint.VisualStudio.Core.Telemetry.Legacy; | ||
using SonarLint.VisualStudio.SLCore.Configuration; | ||
using SonarLint.VisualStudio.SLCore.Service.Lifecycle.Models; | ||
|
||
namespace SonarLint.VisualStudio.SLCore.UnitTests.Configuration; | ||
|
||
[TestClass] | ||
public class SlCoreTelemetryMigrationProviderTests | ||
{ | ||
[TestMethod] | ||
public void MefCtor_CheckIsExported() | ||
{ | ||
MefTestHelpers.CheckTypeCanBeImported<SlCoreTelemetryMigrationProvider, ISlCoreTelemetryMigrationProvider>( | ||
MefTestHelpers.CreateExport<ITelemetryDataRepository>()); | ||
} | ||
|
||
[TestMethod] | ||
public void MefCtor_CheckIsSingleton() | ||
{ | ||
MefTestHelpers.CheckIsSingletonMefComponent<SlCoreTelemetryMigrationProvider>(); | ||
} | ||
|
||
[TestMethod] | ||
public void Get_ConvertsOldTelemetryDataToTelemetryMigration() | ||
{ | ||
var telemetryDataRepository = Substitute.For<ITelemetryDataRepository>(); | ||
telemetryDataRepository.ReadTelemetryData().Returns(new TelemetryData | ||
{ | ||
IsAnonymousDataShared = true, | ||
InstallationDateString = "2017-03-15T06:15:42.1234567+01:00", | ||
NumberOfDaysOfUse = 32 | ||
}); | ||
var slCoreTelemetryMigrationProvider = new SlCoreTelemetryMigrationProvider(telemetryDataRepository); | ||
|
||
var telemetryMigrationDto = slCoreTelemetryMigrationProvider.Get(); | ||
|
||
var expectedDto = new TelemetryMigrationDto( | ||
isEnabled: true, | ||
installTime: new DateTimeOffset(new DateTime(2017, 3, 15, 6, 15, 42, 123, DateTimeKind.Unspecified).AddTicks(4567), TimeSpan.FromHours(1)), | ||
numUseDays: 32); | ||
telemetryMigrationDto.Should().BeEquivalentTo(expectedDto); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.