Merge pull request #7940 from dotnet/merges/release/15.5-to-master-20171031-070033

Merge release/15.5 to master
This commit is contained in:
Livar 2017-11-01 10:02:32 -07:00 committed by GitHub
commit b45f1fb439
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 476 additions and 248 deletions

View file

@ -2,10 +2,10 @@
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CLI_SharedFrameworkVersion>2.1.0-preview1-25830-04</CLI_SharedFrameworkVersion>
<CLI_MSBuild_Version>15.5.0-preview-000165-1081473</CLI_MSBuild_Version>
<CLI_MSBuild_Version>15.5.0-preview-000170-1090113</CLI_MSBuild_Version>
<CLI_Roslyn_Version>2.6.0-beta2-62210-01</CLI_Roslyn_Version>
<CLI_DiaSymNative_Version>1.6.0-beta2-25304</CLI_DiaSymNative_Version>
<CLI_FSharp_Version>4.2.0-rtm-170926-0</CLI_FSharp_Version>
<CLI_FSharp_Version>4.2.0-rtm-171027-0</CLI_FSharp_Version>
<CLI_Deps_Satellites_Build>pre-20171012-1</CLI_Deps_Satellites_Build>
<CLI_Roslyn_Satellites_Version>2.6.0-$(CLI_Deps_Satellites_Build)</CLI_Roslyn_Satellites_Version>
<CLI_FSharp_Satellites_Version>4.4.1-$(CLI_Deps_Satellites_Build)</CLI_FSharp_Satellites_Version>

View file

@ -1,18 +0,0 @@
<!--
***********************************************************************************************
Microsoft.NuGet.ImportAfter.targets
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
created a backup copy. Incorrect changes to this file will make it
impossible to load or build your projects from the command-line or the IDE.
Copyright (c) .NET Foundation. All rights reserved.
***********************************************************************************************
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Import NuGet.targets for Restore -->
<PropertyGroup>
<NuGetRestoreTargets Condition="'$(NuGetRestoreTargets)'==''">$(MSBuildExtensionsPath)\NuGet.targets</NuGetRestoreTargets>
</PropertyGroup>
<Import Condition="Exists('$(NuGetRestoreTargets)')" Project="$(NuGetRestoreTargets)" />
</Project>

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.DotNet.Cli.Utils
{
@ -83,5 +84,11 @@ namespace Microsoft.DotNet.Cli.Utils
public string EventName { get; }
public IDictionary<string, string> Properties { get; }
public IDictionary<string, double> Measurements { get; }
public ApplicationInsightsEntryFormat WithAppliedToPropertiesValue(Func<string, string> func)
{
var appliedProperties = Properties.ToDictionary(p => p.Key, p => func(p.Value));
return new ApplicationInsightsEntryFormat(EventName, appliedProperties, Measurements);
}
}
}

View file

@ -81,6 +81,7 @@ namespace Microsoft.DotNet.Cli
var command = string.Empty;
var lastArg = 0;
var cliFallbackFolderPathCalculator = new CliFallbackFolderPathCalculator();
TopLevelCommandParserResult topLevelCommandParserResult = TopLevelCommandParserResult.Empty;
using (INuGetCacheSentinel nugetCacheSentinel = new NuGetCacheSentinel(cliFallbackFolderPathCalculator))
using (IFirstTimeUseNoticeSentinel disposableFirstTimeUseNoticeSentinel =
new FirstTimeUseNoticeSentinel(cliFallbackFolderPathCalculator))
@ -120,7 +121,13 @@ namespace Microsoft.DotNet.Cli
// It's the command, and we're done!
command = args[lastArg];
if (IsDotnetBeingInvokedFromNativeInstaller(command))
if (string.IsNullOrEmpty(command))
{
command = "help";
}
topLevelCommandParserResult = new TopLevelCommandParserResult(args[lastArg]);
if (IsDotnetBeingInvokedFromNativeInstaller(topLevelCommandParserResult))
{
firstTimeUseNoticeSentinel = new NoOpFirstTimeUseNoticeSentinel();
}
@ -144,7 +151,7 @@ namespace Microsoft.DotNet.Cli
telemetryClient = new Telemetry.Telemetry(firstTimeUseNoticeSentinel);
}
TelemetryEventEntry.Subscribe(telemetryClient.TrackEvent);
TelemetryEventEntry.TelemetryFilter = new TelemetryFilter();
TelemetryEventEntry.TelemetryFilter = new TelemetryFilter(Sha256Hasher.HashWithNormalizedCasing);
}
IEnumerable<string> appArgs =
@ -157,17 +164,12 @@ namespace Microsoft.DotNet.Cli
Console.WriteLine($"Telemetry is: {(telemetryClient.Enabled ? "Enabled" : "Disabled")}");
}
if (string.IsNullOrEmpty(command))
{
command = "help";
}
TelemetryEventEntry.TrackEvent(command, null, null);
TelemetryEventEntry.SendFiltered(topLevelCommandParserResult);
int exitCode;
if (BuiltInCommandsCatalog.Commands.TryGetValue(command, out var builtIn))
if (BuiltInCommandsCatalog.Commands.TryGetValue(topLevelCommandParserResult.Command, out var builtIn))
{
var parseResult = Parser.Instance.ParseFrom($"dotnet {command}", appArgs.ToArray());
var parseResult = Parser.Instance.ParseFrom($"dotnet {topLevelCommandParserResult.Command}", appArgs.ToArray());
if (!parseResult.Errors.Any())
{
TelemetryEventEntry.SendFiltered(parseResult);
@ -178,7 +180,7 @@ namespace Microsoft.DotNet.Cli
else
{
CommandResult result = Command.Create(
"dotnet-" + command,
"dotnet-" + topLevelCommandParserResult.Command,
appArgs,
FrameworkConstants.CommonFrameworks.NetStandardApp15)
.Execute();
@ -187,9 +189,9 @@ namespace Microsoft.DotNet.Cli
return exitCode;
}
private static bool IsDotnetBeingInvokedFromNativeInstaller(string command)
private static bool IsDotnetBeingInvokedFromNativeInstaller(TopLevelCommandParserResult parseResult)
{
return command == "internal-reportinstallsuccess";
return parseResult.Command == "internal-reportinstallsuccess";
}
private static void ConfigureDotNetForFirstTimeUse(

View file

@ -29,9 +29,10 @@ namespace Microsoft.DotNet.Cli.Telemetry
if (firstOption != null)
{
result.Add(new ApplicationInsightsEntryFormat(
"dotnet-" + topLevelCommandNameFromParse,
"sublevelparser/command",
new Dictionary<string, string>
{
{ "verb", topLevelCommandNameFromParse},
{"argument", firstOption}
}));
}

View file

@ -31,9 +31,10 @@ namespace Microsoft.DotNet.Cli.Telemetry
if (firstArgument != null)
{
result.Add(new ApplicationInsightsEntryFormat(
"dotnet-" + topLevelCommandNameFromParse,
"sublevelparser/command",
new Dictionary<string, string>
{
{"verb", topLevelCommandNameFromParse},
{"argument", firstArgument}
}));
}

View file

@ -17,6 +17,11 @@ namespace Microsoft.DotNet.Cli.Telemetry
return HashInFormat(sha256, text);
}
public static string HashWithNormalizedCasing(string text)
{
return Hash(text.ToUpperInvariant());
}
private static string HashInFormat(SHA256 sha256, string text)
{
byte[] bytes = Encoding.UTF8.GetBytes(text);

View file

@ -120,7 +120,7 @@ namespace Microsoft.DotNet.Cli.Telemetry
Dictionary<string, string> eventProperties = GetEventProperties(properties);
Dictionary<string, double> eventMeasurements = GetEventMeasures(measurements);
_client.TrackEvent(eventName, eventProperties, eventMeasurements);
_client.TrackEvent(PrependProducerNamespace(eventName), eventProperties, eventMeasurements);
_client.Flush();
}
catch (Exception e)
@ -129,6 +129,11 @@ namespace Microsoft.DotNet.Cli.Telemetry
}
}
private static string PrependProducerNamespace(string eventName)
{
return "dotnet/cli/" + eventName;
}
private Dictionary<string, double> GetEventMeasures(IDictionary<string, double> measurements)
{
Dictionary<string, double> eventMeasurements = new Dictionary<string, double>(_commonMeasurements);

View file

@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System;
using System.Linq;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
@ -11,48 +12,15 @@ namespace Microsoft.DotNet.Cli.Telemetry
internal class TelemetryFilter : ITelemetryFilter
{
private const string DotnetName = "dotnet";
private readonly Func<string, string> _hash;
public TelemetryFilter(Func<string, string> hash)
{
_hash = hash ?? throw new ArgumentNullException(nameof(hash));
}
public IEnumerable<ApplicationInsightsEntryFormat> Filter(object objectToFilter)
{
var ruleSet = new List<IParseResultLogRule>
{ new AllowListToSendFirstArgument(new HashSet<string>{ "new", "help" }),
new AllowListToSendFirstAppliedOptions(new HashSet<string>{ "add", "remove", "list", "sln", "nuget" }),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> { "new" },
optionsToLog: new HashSet<string> { "language" }
),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> { "build", "publish" },
optionsToLog: new HashSet<string> { "framework", "runtime", "configuration" }
),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> { "run", "clean", "test" },
optionsToLog: new HashSet<string> { "framework", "configuration" }
),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> { "pack" },
optionsToLog: new HashSet<string> { "configuration" }
),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> { "migrate" },
optionsToLog: new HashSet<string> { "sdk-package-version" }
),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> { "vstest" },
optionsToLog: new HashSet<string> { "platform", "framework", "logger" }
),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> { "publish" },
optionsToLog: new HashSet<string> { "runtime" }
)
};
var result = new List<ApplicationInsightsEntryFormat>();
if (objectToFilter is ParseResult parseResult)
@ -62,16 +30,73 @@ namespace Microsoft.DotNet.Cli.Telemetry
{
LogVerbosityForAllTopLevelCommand(result, parseResult, topLevelCommandName);
foreach (IParseResultLogRule rule in ruleSet)
foreach (IParseResultLogRule rule in ParseResultLogRules)
{
result.AddRange(rule.AllowList(parseResult));
}
}
}
else if(objectToFilter is TopLevelCommandParserResult topLevelCommandParserResult)
{
result.Add(new ApplicationInsightsEntryFormat(
"toplevelparser/command",
new Dictionary<string, string>()
{{ "verb", topLevelCommandParserResult.Command}}
));
return result;
}
else if (objectToFilter is InstallerSuccessReport installerSuccessReport)
{
result.Add(new ApplicationInsightsEntryFormat(
"install/reportsuccess",
new Dictionary<string, string> {{ "exeName", installerSuccessReport.ExeName}}
));
}
return result.Select(r => r.WithAppliedToPropertiesValue(_hash)).ToList();
}
private static List<IParseResultLogRule> ParseResultLogRules => new List<IParseResultLogRule>
{
new AllowListToSendFirstArgument(new HashSet<string> {"new", "help"}),
new AllowListToSendFirstAppliedOptions(new HashSet<string> {"add", "remove", "list", "sln", "nuget"}),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> {"new"},
optionsToLog: new HashSet<string> {"language"}
),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> {"build", "publish"},
optionsToLog: new HashSet<string> {"framework", "runtime", "configuration"}
),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> {"run", "clean", "test"},
optionsToLog: new HashSet<string> {"framework", "configuration"}
),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> {"pack"},
optionsToLog: new HashSet<string> {"configuration"}
),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> {"migrate"},
optionsToLog: new HashSet<string> {"sdk-package-version"}
),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> {"vstest"},
optionsToLog: new HashSet<string> {"platform", "framework", "logger"}
),
new TopLevelCommandNameAndOptionToLog
(
topLevelCommandName: new HashSet<string> {"publish"},
optionsToLog: new HashSet<string> {"runtime"}
)
};
private static void LogVerbosityForAllTopLevelCommand(
ICollection<ApplicationInsightsEntryFormat> result,
ParseResult parseResult,
@ -84,9 +109,10 @@ namespace Microsoft.DotNet.Cli.Telemetry
parseResult[DotnetName][topLevelCommandName].AppliedOptions["verbosity"];
result.Add(new ApplicationInsightsEntryFormat(
"dotnet-" + topLevelCommandName,
"sublevelparser/command",
new Dictionary<string, string>()
{
{ "verb", topLevelCommandName},
{"verbosity", appliedOptions.Arguments.ElementAt(0)}
}));
}

View file

@ -36,9 +36,10 @@ namespace Microsoft.DotNet.Cli.Telemetry
parseResult[DotnetName][topLevelCommandName]
.AppliedOptions[option];
result.Add(new ApplicationInsightsEntryFormat(
"dotnet-" + topLevelCommandName,
"sublevelparser/command",
new Dictionary<string, string>
{
{ "verb", topLevelCommandName},
{option, appliedOptions.Arguments.ElementAt(0)}
}));
}

View file

@ -0,0 +1,21 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.DotNet.Cli
{
internal class TopLevelCommandParserResult
{
public static TopLevelCommandParserResult Empty
{
get { return new TopLevelCommandParserResult(string.Empty); }
}
public string Command { get; }
public TopLevelCommandParserResult(string command)
{
Command = command;
}
}
}

View file

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.DotNet.Tools.MSBuild;
@ -10,26 +11,7 @@ namespace Microsoft.DotNet.Tools
{
public class RestoringCommand : MSBuildForwardingApp
{
private bool NoRestore { get; }
private IEnumerable<string> ParsedArguments { get; }
private IEnumerable<string> TrailingArguments { get; }
private IEnumerable<string> ArgsToForwardToRestore()
{
var restoreArguments = ParsedArguments.Where(a =>
!a.StartsWith("/p:TargetFramework"));
if (!restoreArguments.Any(a => a.StartsWith("/verbosity:")))
{
restoreArguments = restoreArguments.Concat(new string[] { "/verbosity:q" });
}
return restoreArguments.Concat(TrailingArguments);
}
private bool ShouldRunImplicitRestore => !NoRestore;
public RestoreCommand SeparateRestoreCommand { get; }
public RestoringCommand(
IEnumerable<string> msbuildArgs,
@ -37,18 +19,64 @@ namespace Microsoft.DotNet.Tools
IEnumerable<string> trailingArguments,
bool noRestore,
string msbuildPath = null)
: base(msbuildArgs, msbuildPath)
: base(GetCommandArguments(msbuildArgs, parsedArguments, noRestore), msbuildPath)
{
NoRestore = noRestore;
ParsedArguments = parsedArguments;
TrailingArguments = trailingArguments;
SeparateRestoreCommand = GetSeparateRestoreCommand(parsedArguments, trailingArguments, noRestore, msbuildPath);
}
private static IEnumerable<string> GetCommandArguments(
IEnumerable<string> msbuildArgs,
IEnumerable<string> parsedArguments,
bool noRestore)
{
if (noRestore)
{
return msbuildArgs;
}
if (HasArgumentToExcludeFromRestore(parsedArguments))
{
return Prepend("/nologo", msbuildArgs);
}
return Prepend("/restore", msbuildArgs);
}
private static RestoreCommand GetSeparateRestoreCommand(
IEnumerable<string> parsedArguments,
IEnumerable<string> trailingArguments,
bool noRestore,
string msbuildPath)
{
if (noRestore || !HasArgumentToExcludeFromRestore(parsedArguments))
{
return null;
}
var restoreArguments = parsedArguments
.Where(a => !IsExcludedFromRestore(a))
.Concat(trailingArguments);
return RestoreCommand.FromArgs(
restoreArguments.ToArray(),
msbuildPath,
noLogo: false);
}
private static IEnumerable<string> Prepend(string argument, IEnumerable<string> arguments)
=> new[] { argument }.Concat(arguments);
private static bool HasArgumentToExcludeFromRestore(IEnumerable<string> arguments)
=> arguments.Any(a => IsExcludedFromRestore(a));
private static bool IsExcludedFromRestore(string argument)
=> argument.StartsWith("/p:TargetFramework=", StringComparison.Ordinal);
public override int Execute()
{
if (ShouldRunImplicitRestore)
if (SeparateRestoreCommand != null)
{
int exitCode = RestoreCommand.Run(ArgsToForwardToRestore().ToArray());
int exitCode = SeparateRestoreCommand.Execute();
if (exitCode != 0)
{
return exitCode;

View file

@ -37,6 +37,8 @@ namespace Microsoft.DotNet.Tools.Build
var appliedBuildOptions = result["dotnet"]["build"];
msbuildArgs.Add($"/clp:Summary");
if (appliedBuildOptions.HasOption("--no-incremental"))
{
msbuildArgs.Add("/t:Rebuild");
@ -50,8 +52,6 @@ namespace Microsoft.DotNet.Tools.Build
msbuildArgs.AddRange(appliedBuildOptions.Arguments);
msbuildArgs.Add($"/clp:Summary");
bool noRestore = appliedBuildOptions.HasOption("--no-restore");
return new BuildCommand(

View file

@ -5,6 +5,7 @@ using System;
using System.Linq;
using System.IO;
using System.Collections.Generic;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Configurer;
using Microsoft.DotNet.Cli.Telemetry;
@ -28,12 +29,13 @@ namespace Microsoft.DotNet.Cli
var result = parser.ParseFrom("dotnet internal-reportinstallsuccess", args);
var internalReportinstallsuccess = result["dotnet"]["internal-reportinstallsuccess"];
var exeName = Path.GetFileName(internalReportinstallsuccess.Arguments.Single());
telemetry.TrackEvent(
"reportinstallsuccess",
new Dictionary<string, string> { { "exeName", exeName } },
new Dictionary<string, double>());
var filter = new TelemetryFilter(Sha256Hasher.HashWithNormalizedCasing);
foreach (var e in filter.Filter(new InstallerSuccessReport(exeName)))
{
telemetry.TrackEvent(e.EventName, e.Properties, null);
}
}
internal class ThreadBlockingTelemetry : ITelemetry
@ -54,4 +56,14 @@ namespace Microsoft.DotNet.Cli
}
}
}
internal class InstallerSuccessReport
{
public string ExeName { get; }
public InstallerSuccessReport(string exeName)
{
ExeName = exeName ?? throw new ArgumentNullException(nameof(exeName));
}
}
}

View file

@ -7,6 +7,7 @@ using Microsoft.Build.Utilities;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.Telemetry;
using Microsoft.DotNet.Configurer;
using System.Collections.Generic;
namespace Microsoft.DotNet.Tools.MSBuild
{
@ -15,6 +16,9 @@ namespace Microsoft.DotNet.Tools.MSBuild
private readonly IFirstTimeUseNoticeSentinel _sentinel =
new FirstTimeUseNoticeSentinel(new CliFallbackFolderPathCalculator());
private readonly ITelemetry _telemetry;
private const string NewEventName = "msbuild";
private const string TargetFrameworkTelemetryEventName = "targetframeworkeval";
private const string TargetFrameworkVersionTelemetryPropertyKey= "TargetFrameworkVersion";
public MSBuildLogger()
{
@ -52,9 +56,24 @@ namespace Microsoft.DotNet.Tools.MSBuild
}
}
internal static void FormatAndSend(ITelemetry telemetry, TelemetryEventArgs args)
{
if (args.EventName == TargetFrameworkTelemetryEventName)
{
var newEventName = $"msbuild/{TargetFrameworkTelemetryEventName}";
Dictionary<string, string> maskedProperties = new Dictionary<string, string>();
if (args.Properties.TryGetValue(TargetFrameworkVersionTelemetryPropertyKey, out string value))
{
maskedProperties.Add(TargetFrameworkVersionTelemetryPropertyKey, Sha256Hasher.HashWithNormalizedCasing(value));
}
telemetry.TrackEvent(newEventName, maskedProperties, measurements: null);
}
}
private void OnTelemetryLogged(object sender, TelemetryEventArgs args)
{
_telemetry.TrackEvent(args.EventName, args.Properties, measurements: null);
FormatAndSend(_telemetry, args);
}
public override void Shutdown()

View file

@ -41,7 +41,7 @@ namespace Microsoft.DotNet.Tools.New
{
if (telemetry.Enabled)
{
telemetry.TrackEvent(name, props, measures);
telemetry.TrackEvent($"template/{name}", props, measures);
}
});
}

View file

@ -19,7 +19,7 @@ namespace Microsoft.DotNet.Tools.Restore
{
}
public static RestoreCommand FromArgs(string[] args, string msbuildPath = null)
public static RestoreCommand FromArgs(string[] args, string msbuildPath = null, bool noLogo = true)
{
DebugHelper.HandleDebugSwitch(ref args);
@ -31,17 +31,15 @@ namespace Microsoft.DotNet.Tools.Restore
var parsedRestore = result["dotnet"]["restore"];
var msbuildArgs = new List<string>
{
"/NoLogo",
"/t:Restore"
};
var msbuildArgs = new List<string>();
if (!HasVerbosityOption(parsedRestore))
if (noLogo)
{
msbuildArgs.Add("/ConsoleLoggerParameters:Verbosity=Minimal");
msbuildArgs.Add("/nologo");
}
msbuildArgs.Add("/t:Restore");
msbuildArgs.AddRange(parsedRestore.OptionValuesToBeForwarded());
msbuildArgs.AddRange(parsedRestore.Arguments);
@ -65,12 +63,5 @@ namespace Microsoft.DotNet.Tools.Restore
return cmd.Execute();
}
private static bool HasVerbosityOption(AppliedOption parsedRestore)
{
return parsedRestore.HasOption("verbosity") ||
parsedRestore.Arguments.Any(a => a.Contains("/v:")) ||
parsedRestore.Arguments.Any(a => a.Contains("/verbosity:"));
}
}
}

View file

@ -10,7 +10,6 @@ namespace Microsoft.DotNet.Cli.MSBuild.Tests
public class GivenDotnetBuildInvocation
{
const string ExpectedPrefix = "exec <msbuildpath> /m /v:m";
const string ExpectedSuffix = "/clp:Summary";
[Theory]
[InlineData(new string[] { }, "/t:Build")]
@ -19,8 +18,6 @@ namespace Microsoft.DotNet.Cli.MSBuild.Tests
[InlineData(new string[] { "--output", "foo" }, "/t:Build /p:OutputPath=foo")]
[InlineData(new string[] { "-o", "foo1 foo2" }, "/t:Build \"/p:OutputPath=foo1 foo2\"")]
[InlineData(new string[] { "--no-incremental" }, "/t:Rebuild")]
[InlineData(new string[] { "-f", "tfm" }, "/t:Build /p:TargetFramework=tfm")]
[InlineData(new string[] { "--framework", "tfm" }, "/t:Build /p:TargetFramework=tfm")]
[InlineData(new string[] { "-r", "rid" }, "/t:Build /p:RuntimeIdentifier=rid")]
[InlineData(new string[] { "--runtime", "rid" }, "/t:Build /p:RuntimeIdentifier=rid")]
[InlineData(new string[] { "-c", "config" }, "/t:Build /p:Configuration=config")]
@ -29,14 +26,45 @@ namespace Microsoft.DotNet.Cli.MSBuild.Tests
[InlineData(new string[] { "--no-dependencies" }, "/t:Build /p:BuildProjectReferences=false")]
[InlineData(new string[] { "-v", "diag" }, "/t:Build /verbosity:diag")]
[InlineData(new string[] { "--verbosity", "diag" }, "/t:Build /verbosity:diag")]
[InlineData(new string[] { "--no-incremental", "-o", "myoutput", "-r", "myruntime", "-v", "diag" }, "/t:Rebuild /p:OutputPath=myoutput /p:RuntimeIdentifier=myruntime /verbosity:diag")]
[InlineData(new string[] { "--no-incremental", "-o", "myoutput", "-r", "myruntime", "-v", "diag", "/ArbitrarySwitchForMSBuild" },
"/t:Rebuild /p:OutputPath=myoutput /p:RuntimeIdentifier=myruntime /verbosity:diag /ArbitrarySwitchForMSBuild")]
public void MsbuildInvocationIsCorrect(string[] args, string expectedAdditionalArgs)
{
expectedAdditionalArgs = (string.IsNullOrEmpty(expectedAdditionalArgs) ? "" : $" {expectedAdditionalArgs}");
var msbuildPath = "<msbuildpath>";
BuildCommand.FromArgs(args, msbuildPath)
.GetProcessStartInfo().Arguments.Should().Be($"{ExpectedPrefix}{expectedAdditionalArgs} {ExpectedSuffix}");
var command = BuildCommand.FromArgs(args, msbuildPath);
command.SeparateRestoreCommand.Should().BeNull();
command.GetProcessStartInfo()
.Arguments.Should()
.Be($"{ExpectedPrefix} /restore /clp:Summary{expectedAdditionalArgs}");
}
[Theory]
[InlineData(new string[] { "-f", "tfm" }, "/t:Restore", "/t:Build /p:TargetFramework=tfm")]
[InlineData(new string[] { "-o", "myoutput", "-f", "tfm", "-v", "diag", "/ArbitrarySwitchForMSBuild" },
"/t:Restore /p:OutputPath=myoutput /verbosity:diag /ArbitrarySwitchForMSBuild",
"/t:Build /p:OutputPath=myoutput /p:TargetFramework=tfm /verbosity:diag /ArbitrarySwitchForMSBuild")]
public void MsbuildInvocationIsCorrectForSeparateRestore(
string[] args,
string expectedAdditionalArgsForRestore,
string expectedAdditionalArgs)
{
expectedAdditionalArgs = (string.IsNullOrEmpty(expectedAdditionalArgs) ? "" : $" {expectedAdditionalArgs}");
var msbuildPath = "<msbuildpath>";
var command = BuildCommand.FromArgs(args, msbuildPath);
command.SeparateRestoreCommand.GetProcessStartInfo()
.Arguments.Should()
.Be($"{ExpectedPrefix} {expectedAdditionalArgsForRestore}");
command.GetProcessStartInfo()
.Arguments.Should()
.Be($"{ExpectedPrefix} /nologo /clp:Summary{expectedAdditionalArgs}");
}
}
}

View file

@ -11,7 +11,7 @@ namespace Microsoft.DotNet.Cli.MSBuild.Tests
{
public class GivenDotnetPackInvocation
{
const string ExpectedPrefix = "exec <msbuildpath> /m /v:m /t:pack";
const string ExpectedPrefix = "exec <msbuildpath> /m /v:m /restore /t:pack";
[Theory]
[InlineData(new string[] { }, "")]
@ -33,8 +33,10 @@ namespace Microsoft.DotNet.Cli.MSBuild.Tests
expectedAdditionalArgs = (string.IsNullOrEmpty(expectedAdditionalArgs) ? "" : $" {expectedAdditionalArgs}");
var msbuildPath = "<msbuildpath>";
PackCommand.FromArgs(args, msbuildPath)
.GetProcessStartInfo().Arguments.Should().Be($"{ExpectedPrefix}{expectedAdditionalArgs}");
var command = PackCommand.FromArgs(args, msbuildPath);
command.SeparateRestoreCommand.Should().BeNull();
command.GetProcessStartInfo().Arguments.Should().Be($"{ExpectedPrefix}{expectedAdditionalArgs}");
}
}
}

View file

@ -20,12 +20,10 @@ namespace Microsoft.DotNet.Cli.MSBuild.Tests
this.output = output;
}
const string ExpectedPrefix = "exec <msbuildpath> /m /v:m /t:Publish";
const string ExpectedPrefix = "exec <msbuildpath> /m /v:m";
[Theory]
[InlineData(new string[] { }, "")]
[InlineData(new string[] { "-f", "<tfm>" }, "/p:TargetFramework=<tfm>")]
[InlineData(new string[] { "--framework", "<tfm>" }, "/p:TargetFramework=<tfm>")]
[InlineData(new string[] { "-r", "<rid>" }, "/p:RuntimeIdentifier=<rid>")]
[InlineData(new string[] { "--runtime", "<rid>" }, "/p:RuntimeIdentifier=<rid>")]
[InlineData(new string[] { "-o", "<publishdir>" }, "/p:PublishDir=<publishdir>")]
@ -43,10 +41,35 @@ namespace Microsoft.DotNet.Cli.MSBuild.Tests
expectedAdditionalArgs = (string.IsNullOrEmpty(expectedAdditionalArgs) ? "" : $" {expectedAdditionalArgs}");
var msbuildPath = "<msbuildpath>";
PublishCommand.FromArgs(args, msbuildPath)
.GetProcessStartInfo()
.Arguments.Should()
.Be($"{ExpectedPrefix}{expectedAdditionalArgs}");
var command = PublishCommand.FromArgs(args, msbuildPath);
command.SeparateRestoreCommand
.Should()
.BeNull();
command.GetProcessStartInfo()
.Arguments.Should()
.Be($"{ExpectedPrefix} /restore /t:Publish{expectedAdditionalArgs}");
}
[Theory]
[InlineData(new string[] { "-f", "<tfm>" }, "/p:TargetFramework=<tfm>")]
[InlineData(new string[] { "--framework", "<tfm>" }, "/p:TargetFramework=<tfm>")]
public void MsbuildInvocationIsCorrectForSeparateRestore(string[] args, string expectedAdditionalArgs)
{
expectedAdditionalArgs = (string.IsNullOrEmpty(expectedAdditionalArgs) ? "" : $" {expectedAdditionalArgs}");
var msbuildPath = "<msbuildpath>";
var command = PublishCommand.FromArgs(args, msbuildPath);
command.SeparateRestoreCommand
.GetProcessStartInfo()
.Arguments.Should()
.Be($"{ExpectedPrefix} /t:Restore");
command.GetProcessStartInfo()
.Arguments.Should()
.Be($"{ExpectedPrefix} /nologo /t:Publish{expectedAdditionalArgs}");
}
[Theory]

View file

@ -11,10 +11,7 @@ namespace Microsoft.DotNet.Cli.MSBuild.Tests
public class GivenDotnetRestoreInvocation
{
private const string ExpectedPrefix =
"exec <msbuildpath> /m /v:m /NoLogo /t:Restore";
private string ExpectedPrefixWithConsoleLoggerParamaters =
$"{ExpectedPrefix} /ConsoleLoggerParameters:Verbosity=Minimal";
"exec <msbuildpath> /m /v:m /nologo /t:Restore";
[Theory]
[InlineData(new string[] { }, "")]
@ -30,19 +27,9 @@ namespace Microsoft.DotNet.Cli.MSBuild.Tests
[InlineData(new string[] { "--no-cache" }, "/p:RestoreNoCache=true")]
[InlineData(new string[] { "--ignore-failed-sources" }, "/p:RestoreIgnoreFailedSources=true")]
[InlineData(new string[] { "--no-dependencies" }, "/p:RestoreRecursive=false")]
public void MsbuildInvocationWithConsoleLoggerParametersIsCorrect(string[] args, string expectedAdditionalArgs)
{
expectedAdditionalArgs = (string.IsNullOrEmpty(expectedAdditionalArgs) ? "" : $" {expectedAdditionalArgs}");
var msbuildPath = "<msbuildpath>";
RestoreCommand.FromArgs(args, msbuildPath)
.GetProcessStartInfo().Arguments
.Should().Be($"{ExpectedPrefixWithConsoleLoggerParamaters}{expectedAdditionalArgs}");
}
[InlineData(new string[] { "-v", "minimal" }, @"/verbosity:minimal")]
[InlineData(new string[] { "--verbosity", "minimal" }, @"/verbosity:minimal")]
public void MsbuildInvocationWithVerbosityIsCorrect(string[] args, string expectedAdditionalArgs)
public void MsbuildInvocationIsCorrect(string[] args, string expectedAdditionalArgs)
{
expectedAdditionalArgs = (string.IsNullOrEmpty(expectedAdditionalArgs) ? "" : $" {expectedAdditionalArgs}");

View file

@ -0,0 +1,76 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using FluentAssertions;
using Xunit;
using Microsoft.DotNet.Tools.MSBuild;
using Microsoft.DotNet.Cli.Telemetry;
using Microsoft.Build.Framework;
using System.Collections.Generic;
namespace Microsoft.DotNet.Cli.MSBuild.Tests
{
public class GivenMSBuildLogger
{
[Fact(DisplayName = "It blocks telemetry that is not in the list")]
public void ItBlocks()
{
var fakeTelemetry = new FakeTelemetry();
var telemetryEventArgs = new TelemetryEventArgs
{
EventName = "User Defined Event Name",
Properties = new Dictionary<string, string>
{
{ "User Defined Key", "User Defined Value"},
}
};
MSBuildLogger.FormatAndSend(fakeTelemetry, telemetryEventArgs);
fakeTelemetry.LogEntry.Should().BeNull();
}
[Fact(DisplayName = "It masks event name with targetframeworkeval only on TargetFrameworkVersion")]
public void ItMasksTargetFrameworkEventname()
{
var fakeTelemetry = new FakeTelemetry();
var telemetryEventArgs = new TelemetryEventArgs
{
EventName = "targetframeworkeval",
Properties = new Dictionary<string, string>
{
{ "TargetFrameworkVersion", ".NETStandard,Version=v2.0"},
}
};
MSBuildLogger.FormatAndSend(fakeTelemetry, telemetryEventArgs);
fakeTelemetry.LogEntry.EventName.Should().Be("msbuild/targetframeworkeval");
fakeTelemetry.LogEntry.Properties.Keys.Count.Should().Be(1);
var expectedKey = "TargetFrameworkVersion";
fakeTelemetry.LogEntry.Properties.Should().ContainKey(expectedKey);
fakeTelemetry.LogEntry.Properties[expectedKey].Should().Be(Sha256Hasher.Hash(".NETSTANDARD,VERSION=V2.0"));
}
public class FakeTelemetry : ITelemetry
{
public bool Enabled { get; set; }
public void TrackEvent(string eventName, IDictionary<string, string> properties, IDictionary<string, double> measurements)
{
LogEntry = new LogEntry { EventName = eventName, Properties = properties, Measurement = measurements };
}
public LogEntry LogEntry { get; private set; }
}
public class LogEntry
{
public string EventName { get; set; }
public IDictionary<string, string> Properties { get; set; }
public IDictionary<string, double> Measurement { get; set; }
}
}
}

View file

@ -17,12 +17,14 @@ namespace Microsoft.DotNet.Tests
private readonly FakeRecordEventNameTelemetry _fakeTelemetry;
public string EventName { get; set; }
public IDictionary<string, string> Properties { get; set; }
public TelemetryCommandTests()
{
_fakeTelemetry = new FakeRecordEventNameTelemetry();
TelemetryEventEntry.Subscribe(_fakeTelemetry.TrackEvent);
TelemetryEventEntry.TelemetryFilter = new TelemetryFilter();
TelemetryEventEntry.TelemetryFilter = new TelemetryFilter(Sha256Hasher.HashWithNormalizedCasing);
}
[Fact]
@ -44,105 +46,133 @@ namespace Microsoft.DotNet.Tests
[Fact]
public void TopLevelCommandNameShouldBeSentToTelemetry()
{
string[] args = {"help"};
string[] args = { "help" };
Cli.Program.ProcessArgs(args);
_fakeTelemetry.LogEntries.Should().Contain(e => e.EventName == args[0]);
_fakeTelemetry.LogEntries.Should().Contain(e => e.EventName == "toplevelparser/command" &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("HELP"));
}
[Fact]
public void DotnetNewCommandFirstArgumentShouldBeSentToTelemetry()
{
const string argumentToSend = "console";
string[] args = {"new", argumentToSend};
string[] args = { "new", argumentToSend };
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-new" && e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == argumentToSend);
.Contain(e => e.EventName == "sublevelparser/command" &&
e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == Sha256Hasher.Hash(argumentToSend.ToUpper()) &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("NEW"));
}
[Fact]
public void DotnetHelpCommandFirstArgumentShouldBeSentToTelemetry()
{
const string argumentToSend = "something";
string[] args = {"help", argumentToSend};
string[] args = { "help", argumentToSend };
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-help" && e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == argumentToSend);
.Contain(e => e.EventName == "sublevelparser/command" &&
e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == Sha256Hasher.Hash(argumentToSend.ToUpper()) &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("HELP"));
}
[Fact]
public void DotnetAddCommandFirstArgumentShouldBeSentToTelemetry()
{
const string argumentToSend = "package";
string[] args = {"add", argumentToSend, "aPackageName"};
string[] args = { "add", argumentToSend, "aPackageName" };
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-add" && e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == argumentToSend);
.Contain(e => e.EventName == "sublevelparser/command" &&
e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == Sha256Hasher.Hash(argumentToSend.ToUpper()) &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("ADD"));
}
[Fact]
public void DotnetAddCommandFirstArgumentShouldBeSentToTelemetry2()
{
const string argumentToSend = "reference";
string[] args = {"add", argumentToSend, "aPackageName"};
string[] args = { "add", argumentToSend, "aPackageName" };
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-add" && e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == argumentToSend);
.Contain(e => e.EventName == "sublevelparser/command" &&
e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == Sha256Hasher.Hash(argumentToSend.ToUpper()) &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("ADD"));
}
[Fact]
public void DotnetRemoveCommandFirstArgumentShouldBeSentToTelemetry()
{
const string argumentToSend = "package";
string[] args = {"remove", argumentToSend, "aPackageName"};
string[] args = { "remove", argumentToSend, "aPackageName" };
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-remove" && e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == argumentToSend);
.Contain(e => e.EventName == "sublevelparser/command" &&
e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == Sha256Hasher.Hash(argumentToSend.ToUpper()) &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("REMOVE"));
}
[Fact]
public void DotnetListCommandFirstArgumentShouldBeSentToTelemetry()
{
const string argumentToSend = "reference";
string[] args = {"list", argumentToSend, "aPackageName"};
string[] args = { "list", argumentToSend, "aPackageName" };
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-list" && e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == argumentToSend);
.Contain(e => e.EventName == "sublevelparser/command" && e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == Sha256Hasher.Hash(argumentToSend.ToUpper()) &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("LIST"));
}
[Fact]
public void DotnetSlnCommandFirstArgumentShouldBeSentToTelemetry()
{
const string argumentToSend = "list";
string[] args = {"sln", "aSolution", argumentToSend};
string[] args = { "sln", "aSolution", argumentToSend };
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-sln" && e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == argumentToSend);
.Contain(e => e.EventName == "sublevelparser/command" &&
e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == Sha256Hasher.Hash(argumentToSend.ToUpper()) &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("SLN"));
}
[Fact]
public void DotnetNugetCommandFirstArgumentShouldBeSentToTelemetry()
{
const string argumentToSend = "push";
string[] args = {"nuget", argumentToSend};
string[] args = { "nuget", argumentToSend };
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-nuget" && e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == argumentToSend);
.Contain(e => e.EventName == "sublevelparser/command" &&
e.Properties.ContainsKey("argument") &&
e.Properties["argument"] == Sha256Hasher.Hash(argumentToSend.ToUpper()) &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("NUGET"));
}
[Fact]
@ -150,12 +180,14 @@ namespace Microsoft.DotNet.Tests
{
const string optionKey = "language";
const string optionValueToSend = "c#";
string[] args = {"new", "console", "--" + optionKey, optionValueToSend};
string[] args = { "new", "console", "--" + optionKey, optionValueToSend };
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-new" && e.Properties.ContainsKey(optionKey) &&
e.Properties[optionKey] == optionValueToSend);
.Contain(e => e.EventName == "sublevelparser/command" && e.Properties.ContainsKey(optionKey) &&
e.Properties[optionKey] == Sha256Hasher.Hash(optionValueToSend.ToUpper()) &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("NEW"));
}
[Fact]
@ -163,12 +195,15 @@ namespace Microsoft.DotNet.Tests
{
const string optionKey = "verbosity";
const string optionValueToSend = "minimal";
string[] args = {"restore", "--" + optionKey, optionValueToSend};
string[] args = { "restore", "--" + optionKey, optionValueToSend };
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-restore" && e.Properties.ContainsKey(optionKey) &&
e.Properties[optionKey] == optionValueToSend);
.Contain(e => e.EventName == "sublevelparser/command" &&
e.Properties.ContainsKey(optionKey) &&
e.Properties[optionKey] == Sha256Hasher.Hash(optionValueToSend.ToUpper()) &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("RESTORE"));
}
[Fact]
@ -176,12 +211,15 @@ namespace Microsoft.DotNet.Tests
{
const string optionKey = "configuration";
const string optionValueToSend = "Debug";
string[] args = {"build", "--" + optionKey, optionValueToSend};
string[] args = { "build", "--" + optionKey, optionValueToSend };
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-build" && e.Properties.ContainsKey(optionKey) &&
e.Properties[optionKey] == optionValueToSend);
.Contain(e => e.EventName == "sublevelparser/command" &&
e.Properties.ContainsKey(optionKey) &&
e.Properties[optionKey] == Sha256Hasher.Hash(optionValueToSend.ToUpper()) &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("BUILD"));
}
[Fact]
@ -193,40 +231,51 @@ namespace Microsoft.DotNet.Tests
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-publish" && e.Properties.ContainsKey(optionKey) &&
e.Properties[optionKey] == optionValueToSend);
.Contain(e => e.EventName == "sublevelparser/command" &&
e.Properties.ContainsKey(optionKey) &&
e.Properties[optionKey] == Sha256Hasher.Hash(optionValueToSend.ToUpper()) &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("PUBLISH"));
}
[Fact]
public void DotnetBuildAndPublishCommandOpinionsShouldBeSentToTelemetryWhenThereIsMultipleOption()
{
string[] args = {"build", "--configuration", "Debug", "--runtime", "osx.10.11-x64"};
string[] args = { "build", "--configuration", "Debug", "--runtime", "osx.10.11-x64" };
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-build" && e.Properties.ContainsKey("configuration") &&
e.Properties["configuration"] == "Debug");
.Contain(e => e.EventName == "sublevelparser/command" && e.Properties.ContainsKey("configuration") &&
e.Properties["configuration"] == Sha256Hasher.Hash("DEBUG") &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("BUILD"));
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-build" && e.Properties.ContainsKey("runtime") &&
e.Properties["runtime"] == "osx.10.11-x64");
.Contain(e => e.EventName == "sublevelparser/command" && e.Properties.ContainsKey("runtime") &&
e.Properties["runtime"] == Sha256Hasher.Hash("OSX.10.11-X64") &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("BUILD"));
}
[Fact]
public void DotnetRunCleanTestCommandOpinionsShouldBeSentToTelemetryWhenThereIsMultipleOption()
{
string[] args = {"clean", "--configuration", "Debug", "--framework", "netcoreapp1.0"};
string[] args = { "clean", "--configuration", "Debug", "--framework", "netcoreapp1.0" };
Cli.Program.ProcessArgs(args);
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-clean" && e.Properties.ContainsKey("configuration") &&
e.Properties["configuration"] == "Debug");
.Contain(e => e.EventName == "sublevelparser/command" && e.Properties.ContainsKey("configuration") &&
e.Properties["configuration"] == Sha256Hasher.Hash("DEBUG") &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("CLEAN"));
_fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "dotnet-clean" && e.Properties.ContainsKey("framework") &&
e.Properties["framework"] == "netcoreapp1.0");
.Contain(e => e.EventName == "sublevelparser/command" && e.Properties.ContainsKey("framework") &&
e.Properties["framework"] == Sha256Hasher.Hash("NETCOREAPP1.0") &&
e.Properties.ContainsKey("verb") &&
e.Properties["verb"] == Sha256Hasher.Hash("CLEAN"));
}
[WindowsOnlyFact]
@ -239,8 +288,8 @@ namespace Microsoft.DotNet.Tests
fakeTelemetry
.LogEntries.Should()
.Contain(e => e.EventName == "reportinstallsuccess" && e.Properties.ContainsKey("exeName") &&
e.Properties["exeName"] == "dotnet-sdk-latest-win-x64.exe");
.Contain(e => e.EventName == "install/reportsuccess" && e.Properties.ContainsKey("exeName") &&
e.Properties["exeName"] == Sha256Hasher.Hash("DOTNET-SDK-LATEST-WIN-X64.EXE"));
}
[Fact]

View file

@ -1,38 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Concurrent;
using System.Collections.Generic;
using Microsoft.DotNet.Cli;
namespace Microsoft.DotNet.Cli.MSBuild.IntegrationTests
{
public class FakeRecordEventNameTelemetry
{
public bool Enabled { get; set; }
public string EventName { get; set; }
public void TrackEvent(string eventName,
IDictionary<string, string> properties,
IDictionary<string, double> measurements)
{
LogEntries.Add(
new LogEntry
{
EventName = eventName,
Measurement = measurements,
Properties = properties
});
}
public ConcurrentBag<LogEntry> LogEntries { get; set; } = new ConcurrentBag<LogEntry>();
public class LogEntry
{
public string EventName { get; set; }
public IDictionary<string, string> Properties { get; set; }
public IDictionary<string, double> Measurement { get; set; }
}
}
}