Skip to content

Commit 4b0acde

Browse files
authored
Refactor the PowerShellRuntime (Azure#16863)
1 parent 65b3e48 commit 4b0acde

File tree

9 files changed

+150
-40
lines changed

9 files changed

+150
-40
lines changed

tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorServiceTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public override int GetHashCode(PredictiveSuggestion suggestion)
6262
private readonly AzPredictorService _noPredictorService;
6363
private readonly AzContext _azContext;
6464

65-
private PowerShellRuntime _powerShellRuntime;
65+
private MockPowerShellRuntime _powerShellRuntime;
6666

6767
/// <summary>
6868
/// Constructs a new instance of <see cref="AzPredictorServiceTests"/>
@@ -71,7 +71,7 @@ public override int GetHashCode(PredictiveSuggestion suggestion)
7171
public AzPredictorServiceTests(ModelFixture fixture)
7272
{
7373
this._fixture = fixture;
74-
_powerShellRuntime = new PowerShellRuntime();
74+
_powerShellRuntime = new MockPowerShellRuntime();
7575
_azContext = new AzContext(_powerShellRuntime);
7676
var startHistory = $"{AzPredictorConstants.CommandPlaceholder}{AzPredictorConstants.CommandConcatenator}{AzPredictorConstants.CommandPlaceholder}";
7777
this._commandBasedPredictor = new CommandLinePredictor(this._fixture.PredictionCollection[startHistory], null, null, _azContext);

tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/CommandLinePredictorTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// limitations under the License.
1313
// ----------------------------------------------------------------------------------
1414

15+
using Microsoft.Azure.PowerShell.Tools.AzPredictor.Test.Mocks;
1516
using Microsoft.Azure.PowerShell.Tools.AzPredictor.Utilities;
1617
using System;
1718
using System.Collections.Generic;
@@ -32,15 +33,15 @@ public sealed class CommandLinePredictorTests : IDisposable
3233
private readonly ModelFixture _fixture;
3334
private readonly CommandLinePredictor _predictor;
3435
private readonly AzContext _azContext;
35-
private PowerShellRuntime _powerShellRuntime;
36+
private MockPowerShellRuntime _powerShellRuntime;
3637

3738
/// <summary>
3839
/// Constructs a new instance of <see cref="CommandLinePredictorTests" />
3940
/// </summary>
4041
public CommandLinePredictorTests(ModelFixture fixture)
4142
{
4243
_fixture = fixture;
43-
_powerShellRuntime = new PowerShellRuntime();
44+
_powerShellRuntime = new MockPowerShellRuntime();
4445
_azContext = new AzContext(_powerShellRuntime);
4546
var startHistory = $"{AzPredictorConstants.CommandPlaceholder}{AzPredictorConstants.CommandConcatenator}{AzPredictorConstants.CommandPlaceholder}";
4647
_predictor = new CommandLinePredictor(_fixture.PredictionCollection[startHistory], null,null, _azContext);
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
using Microsoft.Azure.PowerShell.Tools.AzPredictor.Utilities;
16+
using System;
17+
using System.Collections.Generic;
18+
using System.Management.Automation.Runspaces;
19+
20+
namespace Microsoft.Azure.PowerShell.Tools.AzPredictor.Test.Mocks
21+
{
22+
using PowerShell = System.Management.Automation.PowerShell;
23+
24+
/// <summary>
25+
/// A Mock PowerShell environment to be used in test cases.
26+
/// </summary>
27+
internal sealed class MockPowerShellRuntime : IPowerShellRuntime, IDisposable
28+
{
29+
/// <inheritdoc />
30+
public Runspace DefaultRunspace { get; private set; } = PowerShellRunspaceUtilities.GetMinimalRunspace();
31+
32+
/// <inheritdoc />
33+
public PowerShell ConsoleRuntime => throw new NotImplementedException("It's not implemented yet because there is no test case to set up powershell environment.");
34+
35+
/// <inheritdoc />
36+
public IList<T> ExecuteScript<T>(string contents) => throw new NotImplementedException("It's not implemented yet because there is no test case to set up powershell environment.");
37+
38+
public void Dispose()
39+
{
40+
if (DefaultRunspace is not null)
41+
{
42+
DefaultRunspace.Dispose();
43+
DefaultRunspace = null;
44+
}
45+
}
46+
}
47+
}

tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ParameterSetTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// limitations under the License.
1313
// ----------------------------------------------------------------------------------
1414

15+
using Microsoft.Azure.PowerShell.Tools.AzPredictor.Test.Mocks;
1516
using Microsoft.Azure.PowerShell.Tools.AzPredictor.Utilities;
1617
using System;
1718
using System.Collections.Generic;
@@ -28,14 +29,14 @@ namespace Microsoft.Azure.PowerShell.Tools.AzPredictor.Test
2829
public sealed class ParameterSetTests : IDisposable
2930
{
3031
private readonly AzContext _azContext;
31-
private PowerShellRuntime _powerShellRuntime;
32+
private MockPowerShellRuntime _powerShellRuntime;
3233

3334
/// <summary>
3435
/// Creates a new instance of <see cref="ParameterSetTests" />.
3536
/// </summary>
3637
public ParameterSetTests()
3738
{
38-
_powerShellRuntime = new PowerShellRuntime();
39+
_powerShellRuntime = new MockPowerShellRuntime();
3940
_azContext = new AzContext(_powerShellRuntime);
4041
}
4142

tools/Az.Tools.Predictor/Az.Tools.Predictor/AzContext.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ internal sealed class AzContext : IAzContext
3232
{
3333
private const string InternalUserSuffix = "@microsoft.com";
3434
private static readonly Version DefaultVersion = new Version("0.0.0.0");
35-
private PowerShellRuntime _powerShellRuntime;
35+
private IPowerShellRuntime _powerShellRuntime;
3636

3737
/// <inheritdoc/>
3838
public Version AzVersion { get; private set; } = DefaultVersion;
@@ -129,7 +129,7 @@ public Version ModuleVersion
129129
/// <inheritdoc/>
130130
public bool IsInternal { get; internal set; }
131131

132-
public AzContext(PowerShellRuntime powerShellRuntime) => _powerShellRuntime
132+
public AzContext(IPowerShellRuntime powerShellRuntime) => _powerShellRuntime
133133
= powerShellRuntime;
134134

135135
/// <inheritdoc/>

tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorSurveyHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ internal sealed class AzPredictorSurveyHelper : ISurveyHelper, IDisposable
3535
private DateTime _lastCheckedTime = DateTime.MinValue;
3636
private Timer _promptDelayTimer;
3737

38-
public AzPredictorSurveyHelper(PowerShellRuntime powerShellRuntime)
38+
public AzPredictorSurveyHelper(IPowerShellRuntime powerShellRuntime)
3939
{
4040
var promptMessageScript = @"
4141
if ([Microsoft.Azure.PowerShell.Tools.AzPredictor.AzPredictorData]::ShowSurveyOnIdle) {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
using System.Collections.Generic;
16+
using System.Management.Automation.Runspaces;
17+
18+
namespace Microsoft.Azure.PowerShell.Tools.AzPredictor.Utilities
19+
{
20+
using PowerShell = System.Management.Automation.PowerShell;
21+
22+
/// <summary>
23+
/// A PowerShell environment to run PowerShell cmdlets and scripts.
24+
/// </summary>
25+
internal interface IPowerShellRuntime
26+
{
27+
/// <summary>
28+
/// Gets the minimum PowerShell Runspace. This isn't the necessary the same one as the PowerShell environment that Az
29+
/// Predictor is running on.
30+
/// </summary>
31+
Runspace DefaultRunspace { get; }
32+
33+
/// <summary>
34+
/// The PowerShell environment that the module is imported into.
35+
/// </summary>
36+
/// <remarks>
37+
/// The usage of <see cref="ConsoleRuntime"/> has to be in the context of the running PowerShell thread, for example,
38+
/// the callback of <see cref="PredictorInitializer.OnImport"/>.
39+
/// The callbacks of <see cref="AzPredictor"/> are on a thread pool and it must not be used there.
40+
/// </remarks>
41+
PowerShell ConsoleRuntime { get; }
42+
43+
/// <summary>
44+
/// Executes the PowerShell cmdlet in the current powershell session.
45+
/// </summary>
46+
IList<T> ExecuteScript<T>(string contents);
47+
}
48+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
using System.Management.Automation.Runspaces;
16+
17+
namespace Microsoft.Azure.PowerShell.Tools.AzPredictor.Utilities
18+
{
19+
/// <summary>
20+
/// A provider to create runspace in PowerShell.
21+
/// </summary>
22+
internal class PowerShellRunspaceUtilities
23+
{
24+
/// <summary>
25+
/// Gets a new minimal runspace.
26+
/// </summary>
27+
public static Runspace GetMinimalRunspace()
28+
{
29+
// Create a mini runspace by remove the types and formats
30+
InitialSessionState minimalState = InitialSessionState.CreateDefault2();
31+
// Refer to the remarks for the property DefaultRunspace.
32+
minimalState.Types.Clear();
33+
minimalState.Formats.Clear();
34+
var runspace = RunspaceFactory.CreateRunspace(minimalState);
35+
runspace.Open();
36+
return runspace;
37+
}
38+
}
39+
}

tools/Az.Tools.Predictor/Az.Tools.Predictor/Utilities/PowerShellRuntime.cs

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace Microsoft.Azure.PowerShell.Tools.AzPredictor.Utilities
2727
/// <summary>
2828
/// A PowerShell environment to run PowerShell cmdlets and scripts.
2929
/// </summary>
30-
internal class PowerShellRuntime : IDisposable
30+
internal class PowerShellRuntime : IPowerShellRuntime, IDisposable
3131
{
3232
private PowerShell _runtime;
3333
private PowerShell Runtime
@@ -43,37 +43,13 @@ private PowerShell Runtime
4343
}
4444
}
4545

46-
private readonly Lazy<Runspace> _defaultRunspace = new(() =>
47-
{
48-
// Create a mini runspace by remove the types and formats
49-
InitialSessionState minimalState = InitialSessionState.CreateDefault2();
50-
// Refer to the remarks for the property DefaultRunspace.
51-
minimalState.Types.Clear();
52-
minimalState.Formats.Clear();
53-
var runspace = RunspaceFactory.CreateRunspace(minimalState);
54-
runspace.Open();
55-
return runspace;
56-
});
46+
private readonly Lazy<Runspace> _defaultRunspace = new(() => PowerShellRunspaceUtilities.GetMinimalRunspace());
5747

5848
/// <inheritdoc />
59-
/// <remarks>
60-
/// We don't pre-load Az service modules since they may not always be installed.
61-
/// Creating the instance is at the first time this is called.
62-
/// It can be slow. So the first call must not be in the path of the user interaction.
63-
/// Loading too many modules can also impact user experience because that may add to much memory pressure at the same
64-
/// time.
65-
/// </remarks>
6649
public Runspace DefaultRunspace => _defaultRunspace.Value;
6750

68-
/// <summary>
69-
/// The PowerShell environment that the module is imported into.
70-
/// </summary>
71-
/// <remarks>
72-
/// The usage of <see cref="ConsoleRuntime"/> has to be in the context of the running PowerShell thread, for example,
73-
/// the callback of <see cref="PredictorInitializer.OnImport"/>.
74-
/// The callbacks of <see cref="AzPredictor"/> are on a thread pool and it must not be used there.
75-
/// </remarks>
76-
internal PowerShell ConsoleRuntime = PowerShell.Create(System.Management.Automation.RunspaceMode.CurrentRunspace);
51+
/// <inheritdoc />
52+
public PowerShell ConsoleRuntime { get; } = PowerShell.Create(System.Management.Automation.RunspaceMode.CurrentRunspace);
7753

7854
public void Dispose()
7955
{
@@ -94,9 +70,7 @@ public void Dispose()
9470
}
9571
}
9672

97-
/// <summary>
98-
/// Executes the PowerShell cmdlet in the current powershell session.
99-
/// </summary>
73+
/// <inheritdoc />
10074
public IList<T> ExecuteScript<T>(string contents)
10175
{
10276
Runtime.Commands.Clear();

0 commit comments

Comments
 (0)