diff --git a/.azure-pipelines/powershell-core.yml b/.azure-pipelines/powershell-core.yml index a8ca2518d244..4d0a6674567c 100644 --- a/.azure-pipelines/powershell-core.yml +++ b/.azure-pipelines/powershell-core.yml @@ -13,6 +13,7 @@ variables: BuildTimeoutInMinutes: 120 AnalysisTimeoutInMinutes: 120 TestTimeoutInMinutes: 180 + BuildAzPredictor: false trigger: none diff --git a/.azure-pipelines/util/build-steps.yml b/.azure-pipelines/util/build-steps.yml index 64a2f2c05978..fc640bba7076 100644 --- a/.azure-pipelines/util/build-steps.yml +++ b/.azure-pipelines/util/build-steps.yml @@ -25,11 +25,24 @@ steps: filePath: tools/CheckIgnoredFile.ps1 - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' + displayName: 'Use .NET Core sdk 3.1.x' inputs: packageType: sdk version: 3.1.x +- task: UseDotNet@2 + displayName: 'Use .NET Core sdk 6.0.x' + inputs: + packageType: sdk + version: 6.0.x + +- task: PowerShell@2 + displayName: Setup global.json + inputs: + targetType: inline + script: "$SdkVersion=(dotnet --list-sdks | Select-String '[3,4,5].\\d.\\d{3}').Matches[0].Value; dotnet new globaljson --sdk-version $SdkVersion --force" + pwsh: true + - task: DotNetCoreCLI@2 displayName: Build inputs: @@ -37,6 +50,14 @@ steps: custom: msbuild arguments: 'build.proj /t:Build /p:Configuration=${{ parameters.configuration }};TestFramework=${{ parameters.testFramework }};PullRequestNumber=$(System.PullRequest.PullRequestNumber)' +- task: PowerShell@2 + displayName: Build-AzPredictor + condition: eq(variables.BuildAzPredictor, 'true') + inputs: + targetType: inline + script: "$SdkVersion=(dotnet --list-sdks | Select-String '6.0.\\d{3}').Matches[0].Value; dotnet new globaljson --sdk-version $SdkVersion --force;dotnet msbuild tools/Az.Tools.Predictor/build.proj /t:\"clean;build;test\"" + pwsh: true + - template: publish-artifacts-steps.yml parameters: artifactName: build-${{ parameters.testFramework }} diff --git a/.gitignore b/.gitignore index 9069a2ecb3e6..cf7bd7d87b22 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ SecurityTmp/ tmp/ FilesChanged.txt CsprojMappings.json +global.json obj bin diff --git a/build.proj b/build.proj index f1fbd8e9d44f..e6fbd48a5c4f 100644 --- a/build.proj +++ b/build.proj @@ -163,8 +163,8 @@ - - + + @@ -290,10 +290,6 @@ - - - - diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Az.Tools.Predictor.Test.csproj b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Az.Tools.Predictor.Test.csproj index 304d4b7a6a23..ca78895e9a63 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Az.Tools.Predictor.Test.csproj +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Az.Tools.Predictor.Test.csproj @@ -24,11 +24,16 @@ all + + - - + + diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorServiceTests.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorServiceTests.cs index b413a6cd0fb2..f0c77b14d709 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorServiceTests.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorServiceTests.cs @@ -100,7 +100,7 @@ public void Dispose() [Fact] public void VerifyParameterValues() { - var predictionContext = PredictionContext.Create("Get-AzContext"); + var predictionContext = PredictionContext.Create("Set-Content"); Action actual = () => this._service.GetSuggestion(null, 1, 1, CancellationToken.None); Assert.Throws(actual); @@ -116,14 +116,14 @@ public void VerifyParameterValues() /// Verifies that the prediction comes from the command based list, not the fallback list. /// [Theory] - [InlineData("CONNECT-AZACCOUNT")] - [InlineData("set-azstorageaccount ")] - [InlineData("Get-AzResourceG")] - [InlineData("Get-AzStorageAcco")] - [InlineData("Get-AzKeyVault -VaultName")] - [InlineData("GET-AZSTORAGEACCOUNTKEY -NAME ")] - [InlineData("new-azresourcegroup -name hello")] - [InlineData("new-azresourcegroup hello")] + [InlineData("SET-CONTENT")] + [InlineData("get-logproperties ")] + [InlineData("Clear-C")] + [InlineData("compare-")] + [InlineData("Clear-Variable -Name")] + [InlineData("CLEAR-CONTENT -PATH test")] + [InlineData("Clear-content -path test")] + [InlineData("clear-content ./Test.log")] public void VerifyUsingCommandBasedPredictor(string userInput) { var predictionContext = PredictionContext.Create(userInput); @@ -165,8 +165,8 @@ public void VerifyUsingCommandBasedPredictor(string userInput) /// Verifies that when no prediction is in the command based list, we'll use the fallback list. /// [Theory] - [InlineData("New-AzApiManagementContext -ResourceGroupName hello -Serv")] - [InlineData("Get-AzAlert -TimeRange '1h' -Incl")] + [InlineData("Set-Variable -Name desc -Value ")] + [InlineData("remove-ite")] public void VerifyUsingFallbackPredictor(string userInput) { var predictionContext = PredictionContext.Create(userInput); @@ -209,12 +209,13 @@ public void VerifyUsingFallbackPredictor(string userInput) /// [Theory] [InlineData(AzPredictorConstants.CommandPlaceholder)] + [InlineData("Get-Help")] [InlineData("Get-ChildItem")] - [InlineData("new-azresourcegroup -NoExistingParam")] - [InlineData("get-azaccount ")] - [InlineData("NEW-AZCONTEXT")] + [InlineData("Remove-Item -NoExistingParam")] + [InlineData("get-childitem ")] + [InlineData("NEW-CHILDITEM ")] [InlineData("git status")] - [InlineData("Get-AzContext Name")] + [InlineData("get-item name")] public void VerifyNoPrediction(string userInput) { var predictionContext = PredictionContext.Create(userInput); @@ -235,7 +236,7 @@ public void VerifyNoPrediction(string userInput) /// Verify that it returns null when we cannot parse the user input. /// [Theory] - [InlineData("New-AzVM -Name A $Location")] + [InlineData("Remove-Item -Name A $Location")] public void VerifyFailToParseUserInput(string userInput) { var predictionContext = PredictionContext.Create(userInput); diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTelemetryTests.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTelemetryTests.cs index b2d96ef27bca..c30f438d9e8a 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTelemetryTests.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTelemetryTests.cs @@ -106,7 +106,7 @@ public async Task VerifyOnCommandLineAcceptedForOneSupportedCommandWithoutParame // There is only one command. IReadOnlyList history = new List() { - "Get-AzContext", + "Get-LogProperties" }; azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, history); @@ -149,16 +149,16 @@ public async Task VerifyOnCommandLineAcceptedForOneSupportedCommandWithParameter // There is only one command with parameter. var history = new List() { - "New-AzVM -Name hello -Location WestUS" + "Clear-Variable -Name my* -Scope Global" }; azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, history); azPredictor.OnCommandLineExecuted(MockObjects.PredictionClient, history[0], true); - var maskedCommand = "New-AzVM -Location *** -Name ***"; + var maskedCommand = "Clear-Variable -Name *** -Scope ***"; await telemetryClient.HistoryTaskCompletionSource.Task; - Assert.Equal("New-AzVM -Location *** -Name ***", telemetryClient.HistoryData.Command); + Assert.Equal(maskedCommand, telemetryClient.HistoryData.Command); Assert.Equal(MockObjects.PredictionClient, telemetryClient.HistoryData.Client); VerifyTelemetryDispatchCount(expectedTelemetryCount, telemetryClient); @@ -193,8 +193,8 @@ public async Task VerifyOnCommandLineAcceptedForTwoSupportedCommandHistory() var (azPredictor, telemetryClient) = CreateTestObjects(throwException: false, expectedTelemetryCount); IReadOnlyList history = new List() { - "Get-AzContext", - "New-AzVM -Name hello -Location WestUS", + "Set-Content -Path C:\\Temp\\* -Filter *.txt -Value 'Empty'", + "Get-LogProperties -Name:'Windows PowerShell'" }; azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, history); @@ -202,8 +202,8 @@ public async Task VerifyOnCommandLineAcceptedForTwoSupportedCommandHistory() var maskedCommands = new List() { - "Get-AzContext", - "New-AzVM -Location *** -Name ***", + "Set-Content -Filter *** -Path *** -Value ***", + "Get-LogProperties -Name:***" }; await telemetryClient.HistoryTaskCompletionSource.Task; @@ -291,14 +291,14 @@ public async Task VerifyOnCommandLineAcceptedForUnsupportedCommandAfterSupported var history = new List() { - "New-AzResourceGroup -Name:resourceGroup01", - "New-AzVM -Name hello -Location WestUS" + "Set-Content -Path C:\\Temp\\* -Filter *.txt -Value 'Empty'", + "Get-LogProperties -Name:'Windows PowerShell'" }; var maskedCommands = new List() { - "New-AzResourceGroup -Name:***", - "New-AzVM -Location *** -Name ***" + "Set-Content -Filter *** -Path *** -Value ***", + "Get-LogProperties -Name:***" }; azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, history); @@ -380,14 +380,14 @@ public async Task VerifyOnCommandLineAcceptedForUnsupportedCommandAfterSupported expectedTelemetryCount = 2; telemetryClient.ExceptedTelemetryDispatchCount = expectedTelemetryCount; - history.Add("Get-AzResourceGroup -Name:ResourceGroup01"); + history.Add("Clear-Variable -Name my* -Scope Global"); azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, history); azPredictor.OnCommandLineExecuted(MockObjects.PredictionClient, history.Last(), true); maskedCommands = new List() { - "New-AzVM -Location *** -Name ***", - "Get-AzResourceGroup -Name:***", + "Get-LogProperties -Name:***", + "Clear-Variable -Name *** -Scope ***", }; await telemetryClient.HistoryTaskCompletionSource.Task; @@ -422,7 +422,7 @@ public async Task VerifyOnCommandLineAcceptedForUnsupportedAndSupportedCommands( var history = new List() { "git status", - "New-AzVM -Name:hello -Location:WestUS" + "Set-Content -Path C:\\Temp\\* -Filter *.txt -Value 'Empty'", }; azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, history); @@ -431,7 +431,7 @@ public async Task VerifyOnCommandLineAcceptedForUnsupportedAndSupportedCommands( var maskedCommands = new List() { AzPredictorConstants.CommandPlaceholder, - "New-AzVM -Location:*** -Name:***" + "Set-Content -Filter *** -Path *** -Value ***", }; await telemetryClient.HistoryTaskCompletionSource.Task; @@ -457,7 +457,7 @@ public async Task VerifyOnCommandLineAcceptedForSupportedAndUnsupportedCommands( var (azPredictor, telemetryClient) = CreateTestObjects(throwException: false, expectedTelemetryCount); var history = new List() { - "New-AzVM -Name hello -Location WestUS", + "Get-LogProperties -Name:'Windows PowerShell'", "git status", }; @@ -467,7 +467,7 @@ public async Task VerifyOnCommandLineAcceptedForSupportedAndUnsupportedCommands( var maskedCommands = new List() { AzPredictorConstants.CommandPlaceholder, - "New-AzVM -Location *** -Name ***", + "Get-LogProperties -Name:***", }; await telemetryClient.HistoryTaskCompletionSource.Task; @@ -493,10 +493,10 @@ public async Task VerifyOnCommandLineAcceptedException() var (azPredictor, telemetryClient) = CreateTestObjects(throwException: true, expectedTelemetryCount); var history = new List() { - "New-AzVM -Name hello -Location WestUS", + "Clear-Variable -Name my* -Scope Global", }; - var maskedCommand = "New-AzVM -Location *** -Name ***"; + var maskedCommand = "Clear-Variable -Name *** -Scope ***"; azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, history); azPredictor.OnCommandLineExecuted(MockObjects.PredictionClient, history.Last(), false); @@ -538,7 +538,7 @@ private void VerifySameSuggestionSessionId() var expectedTelemetryCount = 1; var (azPredictor, telemetryClient) = CreateTestObjects(throwException: false, expectedTelemetryCount); - var predictionContext = PredictionContext.Create("New-AzResourceGroup -Name 'ResourceGroup01' -Location 'Central US' -WhatIf"); + var predictionContext = PredictionContext.Create("Clear-Content -Path '*' -Filter '*.log'"); var suggestionPackage = azPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); Assert.Equal(MockObjects.PredictionClient, telemetryClient.GetSuggestionData.Client); @@ -551,7 +551,7 @@ private void VerifySameSuggestionSessionId() Assert.EndsWith("Aggregation", telemetryClient.RecordedTelemetry[0].EventName); Assert.Equal(MockObjects.PredictionClient.Name, telemetryClient.RecordedTelemetry[0].Properties["ClientId"]); var suggestionSessions = JsonSerializer.Deserialize>>(telemetryClient.RecordedTelemetry[0].Properties["Suggestion"]); - Assert.Equal("New-AzResourceGroup -Location *** -Name *** -WhatIf ***", ((JsonElement)(suggestionSessions[0][GetSuggestionTelemetryData.PropertyNameUserInput])).GetString()); + Assert.Equal("Clear-Content -Filter *** -Path ***", ((JsonElement)(suggestionSessions[0][GetSuggestionTelemetryData.PropertyNameUserInput])).GetString()); Assert.Equal(1, ((JsonElement)suggestionSessions[0][GetSuggestionTelemetryData.PropertyNameFound]).GetArrayLength()); var displayCountOrIndex = 3; @@ -602,7 +602,7 @@ public void VerifySuggestionSessionIdChanged() var expectedTelemetryCount = 2; var (azPredictor, telemetryClient) = CreateTestObjects(throwException: false, expectedTelemetryCount); - var predictionContext = PredictionContext.Create("New-AzResourceGroup -Name 'ResourceGroup01' -Location 'Central US' -WhatIf"); + var predictionContext = PredictionContext.Create("Clear-Content -Path '*' -Filter '*.log'"); var firstSuggestionPackage = azPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); var firstGetSuggestionData = telemetryClient.GetSuggestionData; @@ -708,7 +708,7 @@ public void VerifyExceptionInGetSuggestion() var expectedTelemetryCount = 1; var (azPredictor, telemetryClient) = CreateTestObjects(throwException: true, expectedTelemetryCount); - var predictionContext = PredictionContext.Create("New-AzResourceGroup -Name 'ResourceGroup01' -Location 'Central US' -WhatIf"); + var predictionContext = PredictionContext.Create("Clear-Content -Path '*' -Filter '*.log' -Force"); var suggestionPackage = azPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); Assert.IsType(telemetryClient.GetSuggestionData.Exception); @@ -718,7 +718,7 @@ public void VerifyExceptionInGetSuggestion() Assert.EndsWith("Exception", telemetryClient.RecordedTelemetry[0].EventName); Assert.Equal(MockObjects.PredictionClient.Name, telemetryClient.RecordedTelemetry[0].Properties["ClientId"]); - Assert.Equal("New-AzResourceGroup -Location *** -Name *** -WhatIf ***", telemetryClient.RecordedTelemetry[0].Properties["UserInput"]); + Assert.Equal("Clear-Content -Filter *** -Force *** -Path ***", telemetryClient.RecordedTelemetry[0].Properties["UserInput"]); Assert.StartsWith($"Type: {typeof(MockTestException)}\nStack Trace: ", telemetryClient.RecordedTelemetry[0].Properties["Exception"]); Assert.EndsWith("Aggregation", telemetryClient.RecordedTelemetry[1].EventName); @@ -737,13 +737,13 @@ public void VerifyCommandIds() var history = new List() { - "New-AzVM -Name hello -Location WestUS", + "Clear-Variable -Name my* -Scope Global", }; azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, history); azPredictor.OnCommandLineExecuted(MockObjects.PredictionClient, history.Last(), false); - var predictionContext = PredictionContext.Create("New-AzResourceGroup -Name 'ResourceGroup01' -Location 'Central US'"); + var predictionContext = PredictionContext.Create("Clear-Content -Path '*' -Filter '*.log'"); var suggestionPackage = azPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); VerifyTelemetryDispatchCount(expectedTelemetryCount, telemetryClient); @@ -761,7 +761,7 @@ public void VerifyCommandIds() history = new List() { - "Get-AzSqlServer", + "Set-Content -Path C:\\Temp\\* -Filter *.txt -Value 'Empty'", }; azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, history); @@ -792,7 +792,7 @@ public void VerifyCommandIds() telemetryClient.ResetWaitingTasks(); telemetryClient.ExceptedTelemetryDispatchCount = expectedTelemetryCount; - predictionContext = PredictionContext.Create("New-AzResourceGroup -Name 'ResourceGroup01' -Location 'Central US'"); + predictionContext = PredictionContext.Create("Clear-Content -Path '*' -Filter '*.log'"); suggestionPackage = azPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); history =new List() @@ -814,7 +814,7 @@ public void VerifyCommandIds() telemetryClient.ResetWaitingTasks(); telemetryClient.ExceptedTelemetryDispatchCount = expectedTelemetryCount; - predictionContext = PredictionContext.Create("New-AzVM -Name 'VM01' -Location 'Central US'"); + predictionContext = PredictionContext.Create("Clear-Content -Path '*' -Filter '*.log'"); suggestionPackage = azPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); history =new List() @@ -857,7 +857,7 @@ public void VerifyCommandIds() [Fact] public void VerifyAggregationDataSplitAtGetSuggestion() { - var expectedTelemetryCount = 42; + var expectedTelemetryCount = 59; var expectedSuggestionSessionInFirstBatch = expectedTelemetryCount; var (azPredictor, telemetryClient) = CreateTestObjects(throwException: false, expectedTelemetryCount, flushTelemetry: false); @@ -865,7 +865,7 @@ public void VerifyAggregationDataSplitAtGetSuggestion() { // Call the methods a few times to make sure the telemetry data is less than 8092 but the next such call will // make it larger than it. - var predictionContext = PredictionContext.Create($"New-AzResourceGroup -Name 'ResourceGroup{i}' -Location 'Central US' -WhatIf"); + var predictionContext = PredictionContext.Create($"Clear-Content -Path '*' -Filter '{i}.log'"); var _ = azPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); } @@ -881,7 +881,7 @@ public void VerifyAggregationDataSplitAtGetSuggestion() for (int i = 0; i < expectedTelemetryCount; ++i) { // This time make sure that the size exceeds the max property value size with buffer. - var predictionContext = PredictionContext.Create($"New-AzResourceGroup -Name 'NewGroup{i}' -Location 'Central US' -WhatIf"); + var predictionContext = PredictionContext.Create($"Clear-Content -Path '*' -Filter '{i}.log'"); var _ = azPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); } @@ -904,7 +904,7 @@ public void VerifyAggregationDataSplitAtGetSuggestion() [Fact] public void VerifyAggregationDataSplitAtAcceptSuggestion() { - var expectedTelemetryCount = 43; + var expectedTelemetryCount = 64; var expectedSuggestionSessionInFirstBatch = expectedTelemetryCount; var (azPredictor, telemetryClient) = CreateTestObjects(throwException: false, expectedTelemetryCount, flushTelemetry: false); PredictionContext predictionContext = default; @@ -914,11 +914,13 @@ public void VerifyAggregationDataSplitAtAcceptSuggestion() { // Call the methods a few times to make sure the telemetry data is less than 8092 but the next such call will // make it larger than it. - predictionContext = PredictionContext.Create($"New-AzResourceGroup -Name 'ResourceGroup{i}' -Location 'Central US' -WhatIf"); + predictionContext = PredictionContext.Create($"Clear-Variable -Name my* -Scop"); var _ = azPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); } - predictionContext = PredictionContext.Create("Get-AzDefault"); + // It's easier to pad the cached telemetry event with the command without parameters. With parameters, it's more likely to exceed the + // buffer size. + predictionContext = PredictionContext.Create("Get-ChildIte"); suggestionPackage = azPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); VerifyTelemetryDispatchCount(expectedTelemetryCount, telemetryClient); @@ -933,7 +935,7 @@ public void VerifyAggregationDataSplitAtAcceptSuggestion() // But the additional data from SuggestionDisplayedTelemetryData is small so we are still less than the maximum application insight property value size. azPredictor.OnSuggestionDisplayed(MockObjects.PredictionClient, suggestionPackage.Session.Value, 1); // We'll send the first batch contains the found suggestions and displayed info when we process SuggestionAcceptedTelemetryData. - azPredictor.OnSuggestionAccepted(MockObjects.PredictionClient, suggestionPackage.Session.Value, "Get-AzDefault"); + azPredictor.OnSuggestionAccepted(MockObjects.PredictionClient, suggestionPackage.Session.Value, "Get-ChildItem"); VerifyTelemetryDispatchCount(expectedTelemetryCount, telemetryClient); telemetryClient.FlushTelemetry(); @@ -955,7 +957,7 @@ public void VerifyAggregationDataSplitAtAcceptSuggestion() Assert.False(suggestionSessions[0].ContainsKey(GetSuggestionTelemetryData.PropertyNameUserInput)); Assert.False(suggestionSessions[0].ContainsKey(GetSuggestionTelemetryData.PropertyNameIsCancelled)); Assert.Equal(suggestionPackage.Session.Value, ((JsonElement)suggestionSessions[0][GetSuggestionTelemetryData.PropertyNameSuggestionSessionId]).GetUInt32()); - Assert.Equal("Get-AzDefault", ((JsonElement)suggestionSessions[0][SuggestionAcceptedTelemetryData.PropertyNameAccepted]).GetString()); + Assert.Equal("Get-ChildItem", ((JsonElement)suggestionSessions[0][SuggestionAcceptedTelemetryData.PropertyNameAccepted]).GetString()); } /// @@ -964,7 +966,7 @@ public void VerifyAggregationDataSplitAtAcceptSuggestion() [Fact] public void VerifyAggregationDataSplitAtCommandHistory() { - var expectedTelemetryCount = 43; + var expectedTelemetryCount = 64; var expectedSuggestionSessionInFirstBatch = expectedTelemetryCount; var (azPredictor, telemetryClient) = CreateTestObjects(throwException: false, expectedTelemetryCount, flushTelemetry: false); PredictionContext predictionContext = default; @@ -972,13 +974,15 @@ public void VerifyAggregationDataSplitAtCommandHistory() for (int i = 0; i < expectedTelemetryCount - 1; ++i) { - // Call the methods a few times to make sure the telemetry data is less than 8092 but the next such call will + // Call the methods a few times to make sure the telemetry data is less than 8092 but the CommandAccepted and CommandExecuted events // make it larger than it. - predictionContext = PredictionContext.Create($"New-AzResourceGroup -Name 'ResourceGroup{i}' -Location 'Central US' -WhatIf"); - var _ = azPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); + predictionContext = PredictionContext.Create($"Clear-Variable -Name my* -Scop"); + var _ = suggestionPackage = azPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); } - predictionContext = PredictionContext.Create("Get-AzDefault"); + // It's easier to pad the cached telemetry event with the command without parameters. With parameters, it's more likely to exceed the + // buffer size. + predictionContext = PredictionContext.Create("Get-ChildIte"); suggestionPackage = azPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); VerifyTelemetryDispatchCount(expectedTelemetryCount, telemetryClient); @@ -993,8 +997,8 @@ public void VerifyAggregationDataSplitAtCommandHistory() // But the additional data from SuggestionDisplayedTelemetryData is small so we are still less than the maximum application insight property value size. azPredictor.OnSuggestionDisplayed(MockObjects.PredictionClient, suggestionPackage.Session.Value, 1); // We'll send the first batch contains the found suggestions and displayed info when we process SuggestionAcceptedTelemetryData. - azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, new string[] { "Get-AzDefault" }); - azPredictor.OnCommandLineExecuted(MockObjects.PredictionClient, "Get-AzDefault", success: true); + azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, new string[] { "Get-ChildItem" }); + azPredictor.OnCommandLineExecuted(MockObjects.PredictionClient, "Get-ChildItem", success: true); VerifyTelemetryDispatchCount(expectedTelemetryCount, telemetryClient); @@ -1015,7 +1019,7 @@ public void VerifyAggregationDataSplitAtCommandHistory() Assert.False(suggestionSessions[0].ContainsKey(GetSuggestionTelemetryData.PropertyNameUserInput)); Assert.False(suggestionSessions[0].ContainsKey(GetSuggestionTelemetryData.PropertyNameIsCancelled)); Assert.Equal(suggestionPackage.Session.Value, ((JsonElement)suggestionSessions[0][GetSuggestionTelemetryData.PropertyNameSuggestionSessionId]).GetUInt32()); - Assert.Equal("Get-AzDefault", recordedTelemetry.Properties[HistoryTelemetryData.PropertyNameHistory]); + Assert.Equal("Get-ChildItem", recordedTelemetry.Properties[HistoryTelemetryData.PropertyNameHistory]); } private (AzPredictor, MockAzPredictorTelemetryClient) CreateTestObjects(bool throwException, int expectedTelemetryEvent, bool flushTelemetry = true) diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTests.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTests.cs index 27d0135cef45..e14c0354da41 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTests.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTests.cs @@ -92,7 +92,7 @@ public async Task VerifyRequestPredictionForOneSupportedCommandInHistory() { IReadOnlyList history = new List() { - "New-AzVM -Name hello -Location WestUS" + "Get-LogProperties -Name:'Windows PowerShell'" }; _service.Commands = null; @@ -102,7 +102,7 @@ public async Task VerifyRequestPredictionForOneSupportedCommandInHistory() _azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, history); await _service.RequestPredictionTaskCompletionSource.Task; - string maskedCommand = "New-AzVM -Location *** -Name ***"; + string maskedCommand = "Get-LogProperties -Name:***"; Assert.Equal(new List() { AzPredictorConstants.CommandPlaceholder, maskedCommand }, _service.Commands); Assert.Equal(history[0], _service.History.ToString()); @@ -116,8 +116,8 @@ public async Task VerifyRequestPredictionForTwoSupportedCommandInHistory() { IReadOnlyList history = new List() { - "New-AzResourceGroup -Name 'resourceGroup01'", - "New-AzVM -Name:hello -Location:WestUS" + "Set-Content -Path C:\\Temp\\* -Filter *.txt -Value 'Empty'", + "Get-LogProperties -Name:'Windows PowerShell'" }; _service.Commands = null; @@ -129,8 +129,8 @@ public async Task VerifyRequestPredictionForTwoSupportedCommandInHistory() var maskedCommands = new List() { - "New-AzResourceGroup -Name ***", - "New-AzVM -Location:*** -Name:***" + "Set-Content -Filter *** -Path *** -Value ***", + "Get-LogProperties -Name:***" }; Assert.Equal(maskedCommands, _service.Commands); @@ -174,8 +174,8 @@ public async Task VerifyNotTakeUnsupportedCommands() { var history = new List() { - "New-AzResourceGroup -Name:resourceGroup01", - "New-AzVM -Name hello -Location WestUS" + "Set-Content -Path C:\\Temp\\* -Filter *.txt -Value 'Empty'", + "Get-LogProperties -Name:'Windows PowerShell'" }; _service.Commands = null; @@ -200,8 +200,8 @@ public async Task VerifyNotTakeUnsupportedCommands() var maskedCommands = new List() { - "New-AzResourceGroup -Name:***", - "New-AzVM -Location *** -Name ***" + "Set-Content -Filter *** -Path *** -Value ***", + "Get-LogProperties -Name:***" }; Assert.Equal(maskedCommands, _service.Commands); @@ -210,14 +210,14 @@ public async Task VerifyNotTakeUnsupportedCommands() // When there is a new supported command, we'll use that for prediction. _service.ResetRequestPredictionTask(); - history.Add("Get-AzResourceGroup -Name ResourceGroup01"); + history.Add("Clear-Content -Path '*' -Filter '*.log' -Force"); _azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, history); await _service.RequestPredictionTaskCompletionSource.Task; maskedCommands = new List() { - "New-AzVM -Location *** -Name ***", - "Get-AzResourceGroup -Name ***", + "Get-LogProperties -Name:***", + "Clear-Content -Filter *** -Force *** -Path ***" }; Assert.Equal(maskedCommands, _service.Commands); @@ -232,8 +232,8 @@ public async Task VerifyThreeSupportedCommands() { var history = new List() { - "New-AzResourceGroup -Name resourceGroup01", - "New-AzVM -Name:hello -Location:WestUS" + "Set-Content -Path C:\\Temp\\* -Filter *.txt -Value 'Empty'", + "Get-LogProperties -Name:'Windows PowerShell'" }; _service.Commands = null; @@ -244,14 +244,14 @@ public async Task VerifyThreeSupportedCommands() await _service.RequestPredictionTaskCompletionSource.Task; _service.ResetRequestPredictionTask(); - history.Add("Get-AzResourceGroup -Name resourceGroup01"); + history.Add("Clear-Content -Path C:\\Test\\Copy-Script.ps1 -Stream Zone.Identifier"); _azPredictor.OnCommandLineAccepted(MockObjects.PredictionClient, history); await _service.RequestPredictionTaskCompletionSource.Task; var maskedCommands = new List() { - "New-AzVM -Location:*** -Name:***", - "Get-AzResourceGroup -Name ***", + "Get-LogProperties -Name:***", + "Clear-Content -Path *** -Stream ***" }; Assert.Equal(maskedCommands, _service.Commands); @@ -267,7 +267,7 @@ public async Task VerifyUnsupportedAndSupportedCommands() var history = new List() { "git status", - "New-AzVM -Name:hello -Location:WestUS" + "Clear-Content -Path '*' -Filter '*.log' -Force" }; _service.Commands = null; @@ -280,7 +280,7 @@ public async Task VerifyUnsupportedAndSupportedCommands() var maskedCommands = new List() { AzPredictorConstants.CommandPlaceholder, - "New-AzVM -Location:*** -Name:***" + "Clear-Content -Filter *** -Force *** -Path ***" }; Assert.Equal(maskedCommands, _service.Commands); @@ -295,7 +295,7 @@ public async Task VerifySupportedAndUnsupportedCommands() { var history = new List() { - "New-AzVM -Name hello -Location WestUS", + "Clear-Variable -Name:my* -Scope Global", "git status", }; @@ -309,7 +309,7 @@ public async Task VerifySupportedAndUnsupportedCommands() var maskedCommands = new List() { AzPredictorConstants.CommandPlaceholder, - "New-AzVM -Location *** -Name ***", + "Clear-Variable -Name:*** -Scope ***", }; Assert.Equal(maskedCommands, _service.Commands); @@ -320,8 +320,8 @@ public async Task VerifySupportedAndUnsupportedCommands() /// Verifies AzPredictor returns the same value as AzPredictorService for the prediction. /// [Theory] - [InlineData("new-azresourcegroup -name hello")] - [InlineData("Get-AzContext -Name")] + [InlineData("compare-object -referenceobject ref -differenceobject diff")] + [InlineData("Clear-Variable -Name my")] public void VerifySuggestion(string userInput) { var predictionContext = PredictionContext.Create(userInput); @@ -352,8 +352,8 @@ public void VerifySuggestionOnIncompleteCommand() }, azContext); - var userInput = "New-AzResourceGroup -Name 'ResourceGroup01' -Location 'Central US' -WhatIf -"; - var expected = "New-AzResourceGroup -Name 'ResourceGroup01' -Location 'Central US' -WhatIf -Tag value1"; + var userInput = "Clear-Variable -Name my* -"; + var expected = "Clear-Variable -Name my* -Scope Global"; var predictionContext = PredictionContext.Create(userInput); var actual = localAzPredictor.GetSuggestion(MockObjects.PredictionClient, predictionContext, CancellationToken.None); diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/CommandLinePredictorTests.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/CommandLinePredictorTests.cs index d86d9978759e..4ee43178a9ff 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/CommandLinePredictorTests.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/CommandLinePredictorTests.cs @@ -63,7 +63,7 @@ public void Dispose() [Fact] public void VerifyParameterValues() { - var predictionContext = PredictionContext.Create("Get-AzContext"); + var predictionContext = PredictionContext.Create("Remove-Item"); var commandAst = predictionContext.InputAst.FindAll(p => p is CommandAst, true).LastOrDefault() as CommandAst; var commandName = (commandAst?.CommandElements?.FirstOrDefault() as StringConstantExpressionAst)?.Value; var inputParameterSet = new ParameterSet(commandAst, _azContext); @@ -129,10 +129,10 @@ public void VerifyParameterValues() /// Tests in the case there is no prediction for the user input or the user input matches exact what we have in the model. /// [Theory] - [InlineData("NEW-AZCONTEXT")] - [InlineData("get-azaccount ")] + [InlineData("GET-CHILDITEM")] + [InlineData("copy-item ")] [InlineData(AzPredictorConstants.CommandPlaceholder)] - [InlineData("Get-ChildItem")] + [InlineData("Get-LogProperties -Name 'Windows'")] public void GetNoPredictionWithCommandName(string userInput) { var predictionContext = PredictionContext.Create(userInput); @@ -152,14 +152,14 @@ public void GetNoPredictionWithCommandName(string userInput) } /// - /// Tests in the case there are no az commands in the history. + /// Tests in the case when the user inputs only the command name /// [Theory] - [InlineData("New-AzKeyVault ")] - [InlineData("CONNECT-AZACCOUNT")] - [InlineData("set-azstorageaccount ")] - [InlineData("Get-AzResourceG")] - [InlineData("Get-AzStorageAcco")] // an imcomplete command and there is a record "Get-AzStorageAccount" in the model. + [InlineData("Get-LogProperties ")] + [InlineData("CLEAR-VARIABLE")] + [InlineData("compare-object")] + [InlineData("Clear-Con")] + [InlineData("set-con")] public void GetPredictionWithCommandName(string userInput) { var predictionContext = PredictionContext.Create(userInput); @@ -182,10 +182,10 @@ public void GetPredictionWithCommandName(string userInput) /// Tests in the case when the user inputs the command name and parameters. /// [Theory] - [InlineData("Get-AzKeyVault -VaultName")] - [InlineData("GET-AZSTORAGEACCOUNTKEY -NAME ")] - [InlineData("new-azresourcegroup -name hello")] - [InlineData("new-azresourcegroup hello")] + [InlineData("Clear-Variable -Name")] + [InlineData("CLEAR-CONTENT -PATH ")] + [InlineData("set-content -path file")] + [InlineData("set-content file")] public void GetPredictionWithCommandNameParameters(string userInput) { var predictionContext = PredictionContext.Create(userInput); @@ -208,9 +208,9 @@ public void GetPredictionWithCommandNameParameters(string userInput) /// Tests in the case when the user inputs the command name and parameters. /// [Theory] - [InlineData("Get-AzResource -Name hello -Pre")] - [InlineData("Get-AzADServicePrincipal -ApplicationObject")] // Doesn't exist - [InlineData("new-azresourcegroup -NoExistingParam")] + [InlineData("Set-Content -Name hello -Pre")] + [InlineData("Get-ccontent -path ")] // Doesn't exist + [InlineData("get-logproperties -NoExistingParam")] [InlineData("Set-StorageAccount -WhatIf")] [InlineData("git status")] [InlineData("Get-AzContext Name")] // a wrong command @@ -238,7 +238,7 @@ public void GetNoPredictionWithCommandNameParameters(string userInput) [Fact] public void VerifyPredictionForCommand() { - var predictionContext = PredictionContext.Create("Connect-AzAccount"); + var predictionContext = PredictionContext.Create("Set-Content"); var commandAst = predictionContext.InputAst.FindAll(p => p is CommandAst, true).LastOrDefault() as CommandAst; var commandName = (commandAst?.CommandElements?.FirstOrDefault() as StringConstantExpressionAst)?.Value; var inputParameterSet = new ParameterSet(commandAst, _azContext); @@ -252,7 +252,7 @@ public void VerifyPredictionForCommand() 1, CancellationToken.None); - Assert.Equal("Connect-AzAccount -Identity", result.PredictiveSuggestions.First().SuggestionText); + Assert.Equal("Set-Content -Path C:\\Temp\\* -Filter *.txt -Value 'Empty'", result.PredictiveSuggestions.First().SuggestionText); } /// @@ -261,7 +261,7 @@ public void VerifyPredictionForCommand() [Fact] public void VerifyPredictionForCommandAndNamedParameters() { - var predictionContext = PredictionContext.Create("GET-AZSTORAGEACCOUNTKEY -NAME"); + var predictionContext = PredictionContext.Create("set-CONTENT -PATH"); var commandAst = predictionContext.InputAst.FindAll(p => p is CommandAst, true).LastOrDefault() as CommandAst; var commandName = (commandAst?.CommandElements?.FirstOrDefault() as StringConstantExpressionAst)?.Value; var inputParameterSet = new ParameterSet(commandAst, _azContext); @@ -275,7 +275,7 @@ public void VerifyPredictionForCommandAndNamedParameters() 1, CancellationToken.None); - Assert.Equal("Get-AzStorageAccountKey -Name 'myStorageAccount' -ResourceGroupName 'ContosoGroup02'", result.PredictiveSuggestions.First().SuggestionText); + Assert.Equal("Set-Content -Path C:\\Temp\\* -Filter *.txt -Value 'Empty'", result.PredictiveSuggestions.First().SuggestionText); } /// @@ -284,7 +284,7 @@ public void VerifyPredictionForCommandAndNamedParameters() [Fact] public void VerifyPredictionForCommandAndTwoPositionalParameters() { - var predictionContext = PredictionContext.Create("Get-AzStorageAccount test test"); // Two positional parameters with the same value. + var predictionContext = PredictionContext.Create("Compare-Object test test"); // Two positional parameters with the same value. var commandAst = predictionContext.InputAst.FindAll(p => p is CommandAst, true).LastOrDefault() as CommandAst; var commandName = (commandAst?.CommandElements?.FirstOrDefault() as StringConstantExpressionAst)?.Value; var inputParameterSet = new ParameterSet(commandAst, _azContext); @@ -300,8 +300,7 @@ public void VerifyPredictionForCommandAndTwoPositionalParameters() var expected = new PredictiveSuggestion[] { - new PredictiveSuggestion("Get-AzStorageAccount test test -DefaultProfile {IAzureContextContainer}"), - new PredictiveSuggestion("Get-AzStorageAccount test test -IncludeGeoReplicationStats"), + new PredictiveSuggestion("Compare-Object test test -IncludeEqual -ExcludeDifferent"), }; Assert.Equal(expected.Select(e => e.SuggestionText), result.PredictiveSuggestions.Select(r => r.SuggestionText)); @@ -313,7 +312,7 @@ public void VerifyPredictionForCommandAndTwoPositionalParameters() [Fact] public void VerifyPredictionForCommandAndPositionalParameters() { - var predictionContext = PredictionContext.Create("Get-AzStorageAccount resourcegroup"); + var predictionContext = PredictionContext.Create("clear-content file"); var commandAst = predictionContext.InputAst.FindAll(p => p is CommandAst, true).LastOrDefault() as CommandAst; var commandName = (commandAst?.CommandElements?.FirstOrDefault() as StringConstantExpressionAst)?.Value; var inputParameterSet = new ParameterSet(commandAst, _azContext); @@ -329,9 +328,8 @@ public void VerifyPredictionForCommandAndPositionalParameters() var expected = new PredictiveSuggestion[] { - new PredictiveSuggestion("Get-AzStorageAccount resourcegroup -Name 'myStorageAccount'"), - new PredictiveSuggestion("Get-AzStorageAccount resourcegroup -Name 'myStorageAccount' -DefaultProfile {IAzureContextContainer}"), - new PredictiveSuggestion("Get-AzStorageAccount resourcegroup -Name 'myStorageAccount' -IncludeGeoReplicationStats"), + new PredictiveSuggestion("Clear-Content file -Stream Zone.Identifier"), + new PredictiveSuggestion("Clear-Content file -Filter '*.log' -Force"), }; Assert.Equal(expected.Select(e => e.SuggestionText), result.PredictiveSuggestions.Select(r => r.SuggestionText)); diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/CommandsModel.json b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/CommandsModel.json new file mode 100644 index 000000000000..ba51a14afa23 --- /dev/null +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/CommandsModel.json @@ -0,0 +1,59 @@ +{ + "0.0.0": [ + { + "suggestion": "Set-Content -Path C:\\Temp\\* -Filter *.txt -Value 'Empty'", + "description": "Use Filters with Set-Content", + "suggestion count": 462722, + "history count": 4308085 + }, + { + "suggestion": "Get-LogProperties -Name 'Windows PowerShell'", + "description": "Get the configuration settings of the Windows PowerShell event log", + "suggestion count": 24329, + "history count": 286927 + }, + { + "suggestion": "Clear-Content -Path C:\\Test\\Copy-Script.ps1 -Stream Zone.Identifier", + "description": "Clear all data from a stream", + "suggestion count": 438969, + "history count": 86296 + }, + { + "suggestion": "Clear-Content -Path '*' -Filter '*.log' -Force", + "description": "Delete content of all files with a wildcard", + "suggestion count": 689282, + "history count": 869382 + }, + { + "suggestion": "Compare-Object -ReferenceObject $a -DifferenceObject $b -IncludeEqual -ExcludeDifferent", + "description": "Compare each line of content and exclude the differences", + "suggestion count": 686927, + "history count": 769284 + }, + { + "suggestion": "Clear-Variable -Name my* -Scope Global", + "description": "Remove the value of global variables that begin with a search string", + "suggestion count": 686797, + "history count": 6789789 + }, + { + "suggestion": "Set-Variable -Name 'desc' -Value 'A description'", + "description": "Set a variable and get its value", + "suggestion count": 768392, + "history count": 123956 + }, + { + "suggestion": "Remove-Item -Path * -Include *.doc -Exclude *1*", + "description": "Delete some of the document files in a folder", + "suggestion count": 18691, + "history count": 68292 + }, + { + "suggestion": "Get-ChildItem", + "description": "Get child item names", + "suggestion count": 1869, + "history count": 6292 + + } + ] +} diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/CommandsModel.zip b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/CommandsModel.zip deleted file mode 100644 index d9427c192f47..000000000000 Binary files a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/CommandsModel.zip and /dev/null differ diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/PredictionsModel.json b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/PredictionsModel.json new file mode 100644 index 000000000000..c60ba06a90e9 --- /dev/null +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/PredictionsModel.json @@ -0,0 +1,42 @@ +{ + "0.0.0": { + "start_of_snippet\nstart_of_snippet": [ + { + "suggestion": "Set-Content -Path C:\\Temp\\* -Filter *.txt -Value 'Empty'", + "description": "Use Filters with Set-Content", + "suggestion count": 462722, + "history count": 4308085 + }, + { + "suggestion": "Get-LogProperties -Name 'Windows PowerShell'", + "description": "Get the configuration settings of the Windows PowerShell event log", + "suggestion count": 24329, + "history count": 286927 + }, + { + "suggestion": "Clear-Content -Path C:\\Test\\Copy-Script.ps1 -Stream Zone.Identifier", + "description": "Clear all data from a stream", + "suggestion count": 438969, + "history count": 86296 + }, + { + "suggestion": "Clear-Content -Path '*' -Filter '*.log' -Force", + "description": "Delete content of all files with a wildcard", + "suggestion count": 689282, + "history count": 869382 + }, + { + "suggestion": "Compare-Object -ReferenceObject $a -DifferenceObject $b -IncludeEqual -ExcludeDifferent", + "description": "Compare each line of content and exclude the differences", + "suggestion count": 686927, + "history count": 769284 + }, + { + "suggestion": "Clear-Variable -Name my* -Scope Global", + "description": "Remove the value of global variables that begin with a search string", + "suggestion count": 686797, + "history count": 6789789 + } + ] + } +} diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/PredictionsModel.zip b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/PredictionsModel.zip deleted file mode 100644 index 81e5bbe97abe..000000000000 Binary files a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/PredictionsModel.zip and /dev/null differ diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Mocks/MockAzPredictorService.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Mocks/MockAzPredictorService.cs index d8678818bdf3..3094266d9c18 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Mocks/MockAzPredictorService.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Mocks/MockAzPredictorService.cs @@ -71,6 +71,9 @@ public MockAzPredictorService(string history, IList suggestio } } + /// + public override bool IsSupportedCommand(string cmd) => IsRecognizedCommand(cmd); + /// public override Task RequestPredictionsAsync(IEnumerable commands, string requestId, CancellationToken cancellationToken) { diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Mocks/MockPowerShellRuntime.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Mocks/MockPowerShellRuntime.cs index 4b66143e8706..456593fc4e8e 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Mocks/MockPowerShellRuntime.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Mocks/MockPowerShellRuntime.cs @@ -12,7 +12,6 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using Microsoft.Azure.PowerShell.Tools.AzPredictor; using Microsoft.Azure.PowerShell.Tools.AzPredictor.Utilities; using System; using System.Collections.Generic; @@ -27,8 +26,21 @@ namespace Microsoft.Azure.PowerShell.Tools.AzPredictor.Test.Mocks /// internal sealed class MockPowerShellRuntime : IPowerShellRuntime, IDisposable { + private Runspace _defaultRunspace; + /// - public Runspace DefaultRunspace { get; private set; } = PowerShellRunspaceUtilities.GetMinimalRunspace(); + public Runspace DefaultRunspace + { + get + { + if (_defaultRunspace is null) + { + _defaultRunspace = PowerShellRunspaceUtilities.GetTestRunspace(); + } + + return _defaultRunspace; + } + } /// public PowerShell ConsoleRuntime => throw new NotImplementedException("It's not implemented yet because there is no test case to set up powershell environment."); @@ -41,10 +53,10 @@ internal sealed class MockPowerShellRuntime : IPowerShellRuntime, IDisposable public void Dispose() { - if (DefaultRunspace is not null) + if (_defaultRunspace is not null) { - DefaultRunspace.Dispose(); - DefaultRunspace = null; + _defaultRunspace.Dispose(); + _defaultRunspace = null; } } } diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ModelFixture.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ModelFixture.cs index 4f1cc4fe3303..87ce7ecadfe2 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ModelFixture.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ModelFixture.cs @@ -18,6 +18,7 @@ using System.IO; using System.IO.Compression; using System.Linq; +using System.Text; using System.Text.Json; using Xunit; @@ -28,13 +29,11 @@ namespace Microsoft.Azure.PowerShell.Tools.AzPredictor.Test /// public sealed class ModelFixture : IDisposable { - private const string CommandsModelZip = "CommandsModel.zip"; private const string CommandsModelJson = "CommandsModel.json"; - private const string PredictionsModelZip = "PredictionsModel.zip"; private const string PredictionsModelJson = "PredictionsModel.json"; private const string DataDirectoryName = "Data"; - private static readonly Version CommandsVersionToUse = new Version("5.1.0"); - private static readonly Version PredictionsVersionToUse = new Version("5.1.0"); + private static readonly Version CommandsVersionToUse = new Version("0.0.0"); + private static readonly Version PredictionsVersionToUse = new Version("0.0.0"); /// /// Gets a list of string for the commands. @@ -55,8 +54,8 @@ public ModelFixture() var fileInfo = new FileInfo(currentLocation); var directory = fileInfo.DirectoryName; var dataDirectory = Path.Join(directory, ModelFixture.DataDirectoryName); - var commandsModelVersions = JsonSerializer.Deserialize>>(ModelFixture.ReadZipEntry(Path.Join(dataDirectory, ModelFixture.CommandsModelZip), ModelFixture.CommandsModelJson), JsonUtilities.DefaultSerializerOptions); - var predictionsModelVersions = JsonSerializer.Deserialize>>>(ModelFixture.ReadZipEntry(Path.Join(dataDirectory, ModelFixture.PredictionsModelZip), ModelFixture.PredictionsModelJson), JsonUtilities.DefaultSerializerOptions); + var commandsModelVersions = JsonSerializer.Deserialize>>(File.ReadAllText(Path.Join(dataDirectory, ModelFixture.CommandsModelJson), Encoding.UTF8), JsonUtilities.DefaultSerializerOptions); + var predictionsModelVersions = JsonSerializer.Deserialize>>>(File.ReadAllText(Path.Join(dataDirectory, ModelFixture.PredictionsModelJson), Encoding.UTF8), JsonUtilities.DefaultSerializerOptions); var commandsModel = commandsModelVersions[CommandsVersionToUse]; var predictionsModel = predictionsModelVersions[PredictionsVersionToUse]; @@ -79,15 +78,6 @@ public ModelFixture() public void Dispose() { } - - private static string ReadZipEntry(string zipFilePath, string zipEntryName) - { - using ZipArchive zipArchive = ZipFile.Open(zipFilePath, ZipArchiveMode.Read); - var entry = zipArchive.GetEntry(zipEntryName); - - using StreamReader streamReader = new StreamReader(entry.Open()); - return streamReader.ReadToEnd(); - } } /// diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ParameterSetTests.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ParameterSetTests.cs index 8d45691b786a..b4cad05c1ada 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ParameterSetTests.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ParameterSetTests.cs @@ -173,16 +173,16 @@ public void VerifyIncompleteParameterAfterCommandName(string inputData) /// Verify that the incomplete parameter is ignored. /// [Theory] - [InlineData("Get-AzResourceGroup -Name:Test -", false)] - [InlineData("Get-AzResourceGroup -Name Test -", false)] - [InlineData("Get-AzResourceGroup Test -", true)] + [InlineData("Get-LogProperties -Name:name -", false)] + [InlineData("Get-LogProperties -Name name -", false)] + [InlineData("Get-LogProperties name -", true)] public void VerifyIncompleteParameterAtTheEnd(string inputData, bool isPositional) { var predictionContext = PredictionContext.Create(inputData); var commandAst = predictionContext.RelatedAsts.OfType().LastOrDefault(); var expected = new List() { - new Parameter("Name", "Test", isPositional), + new Parameter("Name", "name", isPositional), new Parameter(AzPredictorConstants.DashParameterName, null, false), }; @@ -210,11 +210,11 @@ public void VerifyIncompleteParameterInMiddel(string inputData) [Fact] public void VerifyOnlyOnePositionalParameter() { - var predictionContext = PredictionContext.Create("Get-AzResourceGroup Test"); + var predictionContext = PredictionContext.Create("Get-LogProperties name"); var commandAst = predictionContext.RelatedAsts.OfType().LastOrDefault(); var expected = new List() { - new Parameter("Name", "Test", true), + new Parameter("Name", "name", true), }; var parameterSet = new ParameterSet(commandAst, _azContext); @@ -227,12 +227,12 @@ public void VerifyOnlyOnePositionalParameter() [Fact] public void VerifyTwoPositionalParameters() { - var predictionContext = PredictionContext.Create("Get-AzResourceGroup Test $Location"); + var predictionContext = PredictionContext.Create("Set-Content test.txt abc"); var commandAst = predictionContext.RelatedAsts.OfType().LastOrDefault(); var expected = new List() { - new Parameter("Name", "Test", true), - new Parameter("Location", "$Location", true), + new Parameter("Path", "test.txt", true), + new Parameter("Value", "abc", true), }; var parameterSet = new ParameterSet(commandAst, _azContext); @@ -245,7 +245,8 @@ public void VerifyTwoPositionalParameters() [Fact] public void VerifyExcessPositionalParameters() { - var predictionContext = PredictionContext.Create("Get-AzResourceGroup Name Location Test"); + //var predictionContext = PredictionContext.Create("Get-AzResourceGroup Name Location Test"); + var predictionContext = PredictionContext.Create("Get-LogProperties name test"); var commandAst = predictionContext.RelatedAsts.OfType().LastOrDefault(); Assert.Throws(() => new ParameterSet(commandAst, _azContext)); } @@ -257,13 +258,12 @@ public void VerifyExcessPositionalParameters() public void VerifyPositionalParametersFollowedBySwitchParameters() { - var predictionContext = PredictionContext.Create("Get-AzResourceGroup Test $Location -Pre"); + var predictionContext = PredictionContext.Create(@"Clear-Content C:\*.log -Force"); var commandAst = predictionContext.RelatedAsts.OfType().LastOrDefault(); var expected = new List() { - new Parameter("Name", "Test", true), - new Parameter("Location", "$Location", true), - new Parameter("Pre", null, false), + new Parameter("Path", @"C:\*.log", true), + new Parameter("Force", null, false), }; var parameterSet = new ParameterSet(commandAst, _azContext); @@ -276,12 +276,12 @@ public void VerifyPositionalParametersFollowedBySwitchParameters() [Fact] public void VerifyPositionalParametersFollowedByNamedParameters() { - var predictionContext = PredictionContext.Create("Get-AzResourceGroup Test -Location:$Location"); + var predictionContext = PredictionContext.Create(@"Get-Content C:\Copy-Script.ps1 -Stream Zone.Identifier"); var commandAst = predictionContext.RelatedAsts.OfType().LastOrDefault(); var expected = new List() { - new Parameter("Name", "Test", true), - new Parameter("Location", "$Location", false), + new Parameter("Path", @"C:\Copy-Script.ps1", true), + new Parameter("Stream", "Zone.Identifier", false), }; var parameterSet = new ParameterSet(commandAst, _azContext); diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorService.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorService.cs index 229a75e66253..d380c21ecac0 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorService.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorService.cs @@ -323,10 +323,17 @@ public virtual void RecordHistory(CommandAst history) => }); /// - public bool IsSupportedCommand(string cmd) => IsRecognizedCommand(cmd) + public virtual bool IsSupportedCommand(string cmd) => IsRecognizedCommand(cmd) && !_surveyCmdlets.Any(cmdlet => cmdlet.Command.StartsWith(cmd, StringComparison.OrdinalIgnoreCase)) // the survey cmdlets aren't in the normal az command flow, so mark them as unsupported. && cmd.IndexOf(AzPredictorConstants.AzCommandMoniker) > 0; // This is the Az cmdlet. + /// + /// Checks whether the given is in the command list. + /// + /// The command to check if it's in the list. + protected bool IsRecognizedCommand(string cmd) => !string.IsNullOrWhiteSpace(cmd) + && (_allPredictiveCommands?.Contains(cmd) == true); + /// /// Requests a list of popular commands from service. These commands are used as fall back suggestion /// if none of the predictions fit for the current input. This method should be called once per session. @@ -441,8 +448,5 @@ private static void SetHttpRequestHeader(HttpRequestHeaders header, string idToT } } } - - private bool IsRecognizedCommand(string cmd) => !string.IsNullOrWhiteSpace(cmd) - && (_allPredictiveCommands?.Contains(cmd) == true); } } diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/Utilities/PowerShellRunspaceUtilities.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/Utilities/PowerShellRunspaceUtilities.cs index ea4ab5993058..ce666cf5b65c 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/Utilities/PowerShellRunspaceUtilities.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/Utilities/PowerShellRunspaceUtilities.cs @@ -12,6 +12,7 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using Microsoft.PowerShell; using System.Management.Automation.Runspaces; namespace Microsoft.Azure.PowerShell.Tools.AzPredictor.Utilities @@ -24,10 +25,26 @@ internal class PowerShellRunspaceUtilities /// /// Gets a new minimal runspace. /// - public static Runspace GetMinimalRunspace() + public static Runspace GetMinimalRunspace() => GetRunspace(ExecutionPolicy.Default); + + /// + /// Gets a new minimal runspace that's tweak for unit tests. + /// + /// + /// This returns the runspace with ExecutionPolicy.RemoteSigned. In the unit tests, we need to load + /// the modules copied to the test folder. So RemoteSigned is required to be able to load them. + /// Other than that, the settings should be the same as . + /// + internal static Runspace GetTestRunspace() => GetRunspace(ExecutionPolicy.RemoteSigned); + + private static Runspace GetRunspace(ExecutionPolicy executionPolicy) { // Create a mini runspace by remove the types and formats InitialSessionState minimalState = InitialSessionState.CreateDefault2(); + if (executionPolicy != ExecutionPolicy.Default) + { + minimalState.ExecutionPolicy = executionPolicy; + } // Refer to the remarks for the property DefaultRunspace. minimalState.Types.Clear(); minimalState.Formats.Clear();