diff --git a/Azure.PowerShell.Common.Netcore.sln b/Azure.PowerShell.Common.Netcore.sln
index 123712d739..f996775090 100644
--- a/Azure.PowerShell.Common.Netcore.sln
+++ b/Azure.PowerShell.Common.Netcore.sln
@@ -43,6 +43,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Compute.Test.Netcore", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Strategies.Test.Netcore", "src\Strategies.Test\Strategies.Test.Netcore.csproj", "{6756A7F2-1141-4065-BA23-0C555D2A2BC3}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFx.Netcore", "src\TestFx\TestFx.Netcore.csproj", "{1E20E5A0-3353-4888-9B29-AE1A2C1C8DD0}"
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Authentication.Test.Netcore", "src\Authentication.Test\Authentication.Test.Netcore.csproj", "{78D9B754-6A18-4125-80CC-63437BDE3244}"
EndProject
Global
@@ -127,6 +129,10 @@ Global
{6756A7F2-1141-4065-BA23-0C555D2A2BC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6756A7F2-1141-4065-BA23-0C555D2A2BC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6756A7F2-1141-4065-BA23-0C555D2A2BC3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1E20E5A0-3353-4888-9B29-AE1A2C1C8DD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1E20E5A0-3353-4888-9B29-AE1A2C1C8DD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1E20E5A0-3353-4888-9B29-AE1A2C1C8DD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1E20E5A0-3353-4888-9B29-AE1A2C1C8DD0}.Release|Any CPU.Build.0 = Release|Any CPU
{78D9B754-6A18-4125-80CC-63437BDE3244}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{78D9B754-6A18-4125-80CC-63437BDE3244}.Debug|Any CPU.Build.0 = Debug|Any CPU
{78D9B754-6A18-4125-80CC-63437BDE3244}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/Azure.PowerShell.Common.sln b/Azure.PowerShell.Common.sln
index 5e2110e060..d8956bcafc 100644
--- a/Azure.PowerShell.Common.sln
+++ b/Azure.PowerShell.Common.sln
@@ -51,6 +51,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Strategies.Test", "src\Stra
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScenarioTest", "src\ScenarioTest\ScenarioTest.csproj", "{C1BDA476-A5CC-4394-914D-48B0EC31A710}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestFx", "src\TestFx\TestFx.csproj", "{8C625DE3-0067-454A-AF2C-EFD672EEB31A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -149,6 +151,10 @@ Global
{C1BDA476-A5CC-4394-914D-48B0EC31A710}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C1BDA476-A5CC-4394-914D-48B0EC31A710}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C1BDA476-A5CC-4394-914D-48B0EC31A710}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8C625DE3-0067-454A-AF2C-EFD672EEB31A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8C625DE3-0067-454A-AF2C-EFD672EEB31A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8C625DE3-0067-454A-AF2C-EFD672EEB31A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8C625DE3-0067-454A-AF2C-EFD672EEB31A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/build/sign.proj b/build/sign.proj
index 34e1de6f6d..54d3a9bf3f 100644
--- a/build/sign.proj
+++ b/build/sign.proj
@@ -23,6 +23,7 @@
+
diff --git a/src/Aks/Aks.Netcore.csproj b/src/Aks/Aks.Netcore.csproj
index 0e6ccd53b2..65eebb0f6c 100644
--- a/src/Aks/Aks.Netcore.csproj
+++ b/src/Aks/Aks.Netcore.csproj
@@ -1,8 +1,8 @@
-
-
+
+
netstandard2.0
Microsoft.Azure.PowerShell.Aks
Microsoft.Azure.Commands.Common.Aks
diff --git a/src/Dependencies.Test.targets b/src/Dependencies.Test.targets
index a9ba56fd6e..e26736eed4 100644
--- a/src/Dependencies.Test.targets
+++ b/src/Dependencies.Test.targets
@@ -5,9 +5,9 @@
-
-
-
+
+
+
diff --git a/src/ScenarioTest.ResourceManager/EnvironmentSetupHelper.cs b/src/ScenarioTest.ResourceManager/EnvironmentSetupHelper.cs
index 199dc2715b..b89a7a60d2 100644
--- a/src/ScenarioTest.ResourceManager/EnvironmentSetupHelper.cs
+++ b/src/ScenarioTest.ResourceManager/EnvironmentSetupHelper.cs
@@ -585,9 +585,7 @@ public void SetupModulesFromCommon(AzureModule mode, params string[] modules)
public void SetupModules(params string[] modules)
{
- this.modules = new List();
- this.modules.Add("Assert.ps1");
- this.modules.Add("Common.ps1");
+ this.modules = new List {"Assert.ps1", "Common.ps1"};
this.modules.AddRange(modules);
}
@@ -597,14 +595,18 @@ public virtual Collection RunPowerShellTest(params string[] scripts)
// permissive record matcher.
if (HttpMockServer.Matcher == null || HttpMockServer.Matcher.GetType() == typeof(SimpleRecordMatcher))
{
- Dictionary d = new Dictionary();
- d.Add("Microsoft.Resources", null);
- d.Add("Microsoft.Features", null);
- d.Add("Microsoft.Authorization", null);
- d.Add("Microsoft.Compute", null);
- d.Add("Microsoft.KeyVault", null);
- var providersToIgnore = new Dictionary();
- providersToIgnore.Add("Microsoft.Azure.Management.Resources.ResourceManagementClient", "2016-02-01");
+ var d = new Dictionary
+ {
+ {"Microsoft.Resources", null},
+ {"Microsoft.Features", null},
+ {"Microsoft.Authorization", null},
+ {"Microsoft.Compute", null},
+ {"Microsoft.KeyVault", null}
+ };
+ var providersToIgnore = new Dictionary
+ {
+ {"Microsoft.Azure.Management.Resources.ResourceManagementClient", "2016-02-01"}
+ };
HttpMockServer.Matcher = new PermissiveRecordMatcherWithApiExclusion(true, d, providersToIgnore);
}
@@ -613,13 +615,10 @@ public virtual Collection RunPowerShellTest(params string[] scripts)
SetupPowerShellModules(powershell);
Collection output = null;
- for (int i = 0; i < scripts.Length; ++i)
+ foreach (var script in scripts)
{
- if (TracingInterceptor != null)
- {
- TracingInterceptor.Information(scripts[i]);
- }
- powershell.AddScript(scripts[i]);
+ TracingInterceptor?.Information(script);
+ powershell.AddScript(script);
}
try
{
@@ -627,12 +626,7 @@ public virtual Collection RunPowerShellTest(params string[] scripts)
if (powershell.Streams.Error.Count > 0)
{
throw new RuntimeException(
- string.Format(
- "Test failed due to a non-empty error stream. First error: {0}{1}",
- PowerShellExtensions.FormatErrorRecord(powershell.Streams.Error[0]),
- powershell.Streams.Error.Count > 0
- ? "Check the error stream in the test log for additional errors."
- : ""));
+ $"Test failed due to a non-empty error stream. First error: {PowerShellExtensions.FormatErrorRecord(powershell.Streams.Error[0])}{(powershell.Streams.Error.Count > 0 ? "Check the error stream in the test log for additional errors." : "")}");
}
return output;
@@ -660,13 +654,14 @@ private void SetupPowerShellModules(System.Management.Automation.PowerShell powe
}
#endif
powershell.AddScript("$error.clear()");
- powershell.AddScript(string.Format("Write-Debug \"current directory: {0}\"", System.AppDomain.CurrentDomain.BaseDirectory));
- powershell.AddScript(string.Format("Write-Debug \"current executing assembly: {0}\"", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)));
- powershell.AddScript(string.Format("cd \"{0}\"", System.AppDomain.CurrentDomain.BaseDirectory));
+ powershell.AddScript($"Write-Debug \"current directory: {System.AppDomain.CurrentDomain.BaseDirectory}\"");
+ powershell.AddScript(
+ $"Write-Debug \"current executing assembly: {Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}\"");
+ powershell.AddScript($"cd \"{System.AppDomain.CurrentDomain.BaseDirectory}\"");
- foreach (string moduleName in modules)
+ foreach (var moduleName in modules)
{
- powershell.AddScript(string.Format("Import-Module \"{0}\"", moduleName.AsAbsoluteLocation()));
+ powershell.AddScript($"Import-Module \"{moduleName.AsAbsoluteLocation()}\"");
if (moduleName.EndsWith(".psd1"))
{
#if NETSTANDARD
@@ -682,8 +677,8 @@ private void SetupPowerShellModules(System.Management.Automation.PowerShell powe
powershell.AddScript("Disable-AzureRmDataCollection -ErrorAction Ignore");
powershell.AddScript(
- string.Format("set-location \"{0}\"", System.AppDomain.CurrentDomain.BaseDirectory));
- powershell.AddScript(string.Format(@"$TestOutputRoot='{0}'", System.AppDomain.CurrentDomain.BaseDirectory));
+ $"set-location \"{System.AppDomain.CurrentDomain.BaseDirectory}\"");
+ powershell.AddScript($@"$TestOutputRoot='{System.AppDomain.CurrentDomain.BaseDirectory}'");
powershell.AddScript("$VerbosePreference='Continue'");
powershell.AddScript("$DebugPreference='Continue'");
powershell.AddScript("$ErrorActionPreference='Stop'");
diff --git a/src/ScenarioTest.ResourceManager/ScenarioTest.ResourceManager.csproj b/src/ScenarioTest.ResourceManager/ScenarioTest.ResourceManager.csproj
index fc735d0ecd..ab3feb38dd 100644
--- a/src/ScenarioTest.ResourceManager/ScenarioTest.ResourceManager.csproj
+++ b/src/ScenarioTest.ResourceManager/ScenarioTest.ResourceManager.csproj
@@ -1,5 +1,8 @@
+
+ false
+
Debug
diff --git a/src/ScenarioTest/ScenarioTest.csproj b/src/ScenarioTest/ScenarioTest.csproj
index feff97fb8f..f84a32a92a 100644
--- a/src/ScenarioTest/ScenarioTest.csproj
+++ b/src/ScenarioTest/ScenarioTest.csproj
@@ -2,6 +2,7 @@
true
+ false
diff --git a/src/TestFx/ITestRunner.cs b/src/TestFx/ITestRunner.cs
new file mode 100644
index 0000000000..b833046a97
--- /dev/null
+++ b/src/TestFx/ITestRunner.cs
@@ -0,0 +1,21 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+namespace Microsoft.Azure.Commands.TestFx
+{
+ public interface ITestRunner
+ {
+ void RunTestScript(params string[] scripts);
+ }
+}
diff --git a/src/TestFx/ITestRunnerFactory.cs b/src/TestFx/ITestRunnerFactory.cs
new file mode 100644
index 0000000000..ee3669b94e
--- /dev/null
+++ b/src/TestFx/ITestRunnerFactory.cs
@@ -0,0 +1,32 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using Microsoft.WindowsAzure.Commands.ScenarioTest;
+
+namespace Microsoft.Azure.Commands.TestFx
+{
+ public interface ITestRunnerFactory
+ {
+ ITestRunner Build();
+ ITestRunnerFactory WithProjectSubfolderForTests(string folderName);
+ ITestRunnerFactory WithCommonPsScripts(string[] psScriptList);
+ ITestRunnerFactory WithNewPsScriptFilename(string psScriptName);
+ ITestRunnerFactory WithExtraRmModules(Func buildModuleList);
+ ITestRunnerFactory WithNewRmModules(Func buildModuleList);
+ ITestRunnerFactory WithExtraUserAgentsToIgnore(Dictionary userAgentsToIgnore);
+ ITestRunnerFactory WithRecordMatcher(RecordMatcherDelegate recordMatcher);
+ }
+}
diff --git a/src/TestFx/Properties/AssemblyInfo.cs b/src/TestFx/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..b886e27102
--- /dev/null
+++ b/src/TestFx/Properties/AssemblyInfo.cs
@@ -0,0 +1,32 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Microsoft Azure PowerShell TestFx")]
+[assembly: AssemblyDescription("Microsoft Azure PowerShell TestFx library. Only for use with the Azure PowerShell runtime. Not intended for general development use.")]
+[assembly: AssemblyProduct("Microsoft Azure PowerShell")]
+[assembly: AssemblyCompany("Microsoft Corporation")]
+[assembly: AssemblyCopyright("Copyright © Microsoft Corporation")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("8c625de3-0067-454a-af2c-efd672eeb31a")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/TestFx/TestClientFactory.cs b/src/TestFx/TestClientFactory.cs
new file mode 100644
index 0000000000..9f6fac9aea
--- /dev/null
+++ b/src/TestFx/TestClientFactory.cs
@@ -0,0 +1,144 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using Hyak.Common;
+using Microsoft.Azure.Commands.Common.Authentication;
+using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
+using Microsoft.Azure.Commands.Common.Authentication.Models;
+using Microsoft.Azure.Graph.RBAC.Version1_6;
+using Microsoft.Rest;
+using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
+
+namespace Microsoft.Azure.Commands.TestFx
+{
+ public class TestClientFactory : IClientFactory
+ {
+ private readonly MockContext _mockContext;
+
+ public TestClientFactory(MockContext mockContext)
+ {
+ _mockContext = mockContext ?? throw new ArgumentNullException(nameof(mockContext));
+ }
+
+ public TClient CreateArmClient(IAzureContext context, string endpoint) where TClient : Rest.ServiceClient
+ {
+ if (typeof(TClient) != typeof(GraphRbacManagementClient))
+ {
+ return _mockContext.GetServiceClient();
+ }
+
+ var graphClient = _mockContext.GetGraphServiceClient();
+ graphClient.TenantID = context.Tenant.Id;
+ return graphClient as TClient;
+ }
+
+ public TClient CreateCustomArmClient(params object[] parameters) where TClient : Rest.ServiceClient
+ {
+ return _mockContext.GetServiceClient();
+ }
+
+ public HttpClient CreateHttpClient(string endpoint, ICredentials credentials)
+ {
+ throw new NotImplementedException();
+ }
+
+ public HttpClient CreateHttpClient(string endpoint, HttpMessageHandler effectiveHandler)
+ {
+ throw new NotImplementedException();
+ }
+
+ #region Action and Handler
+
+ public void AddAction(IClientAction action)
+ {
+ // Do nothing
+ }
+
+ public void RemoveAction(Type actionType)
+ {
+ // Do nothing
+ }
+
+ public void AddHandler(T handler) where T : DelegatingHandler, ICloneable
+ {
+ // Do nothing
+ }
+
+ public void RemoveHandler(Type handlerType)
+ {
+ // Do nothing
+ }
+ public DelegatingHandler[] GetCustomHandlers()
+ {
+ // Do nothing
+ return new DelegatingHandler[0];
+ }
+
+ #endregion
+
+ #region UserAgent
+
+ public HashSet UniqueUserAgents { get; set; } = new HashSet();
+
+ public void AddUserAgent(string productName, string productVersion)
+ {
+ UniqueUserAgents.Add(new ProductInfoHeaderValue(productName, productVersion));
+ }
+
+ public void AddUserAgent(string productName)
+ {
+ AddUserAgent(productName, string.Empty);
+ }
+
+ public void RemoveUserAgent(string name)
+ {
+ UniqueUserAgents.RemoveWhere(p => string.Equals(p.Product.Name, name, StringComparison.OrdinalIgnoreCase));
+ }
+
+ public ProductInfoHeaderValue[] UserAgents => UniqueUserAgents.ToArray();
+
+ #endregion
+
+ #region Hyak
+
+ public TClient CreateClient(IAzureContext context, string endpoint) where TClient : Hyak.Common.ServiceClient
+ {
+ throw new NotImplementedException();
+ }
+
+ public TClient CreateClient(IAzureContextContainer profile, string endpoint) where TClient : Hyak.Common.ServiceClient
+ {
+ throw new NotImplementedException();
+ }
+
+ public TClient CreateClient(IAzureContextContainer profile, IAzureSubscription subscription, string endpoint) where TClient : Hyak.Common.ServiceClient
+ {
+ throw new NotImplementedException();
+ }
+
+ public TClient CreateCustomClient(params object[] parameters) where TClient : Hyak.Common.ServiceClient
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/TestFx/TestFx.Netcore.csproj b/src/TestFx/TestFx.Netcore.csproj
new file mode 100644
index 0000000000..6983f96b10
--- /dev/null
+++ b/src/TestFx/TestFx.Netcore.csproj
@@ -0,0 +1,56 @@
+
+
+
+
+
+ netstandard2.0
+ Microsoft.Azure.PowerShell.TestFx
+ Microsoft.Azure.Commands.TestFx
+ $(ProjectDir)..\..\artifacts\$(Configuration)
+ true
+
+ false
+
+
+
+ Microsoft Azure PowerShell TestFx
+ Microsoft Azure PowerShell TestFx library. Only for use with the Azure PowerShell runtime. Not intended for general development use.
+ azure;powershell;testfx
+ Microsoft Corporation
+ Copyright © Microsoft Corporation
+ https://aka.ms/azps-common-license
+ https://github.com/Azure/azure-powershell-common
+ $(ProjectDir)..\..\artifacts\Package\$(Configuration)
+ true
+ 1.0.0-preview
+
+
+
+ false
+ TRACE;DEBUG;NETSTANDARD
+
+
+
+ true
+ true
+ ..\MSSharedLibKey.snk
+ TRACE;RELEASE;NETSTANDARD;SIGN
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/TestFx/TestFx.csproj b/src/TestFx/TestFx.csproj
new file mode 100644
index 0000000000..22d11bac8e
--- /dev/null
+++ b/src/TestFx/TestFx.csproj
@@ -0,0 +1,78 @@
+
+
+
+ false
+
+
+
+ Debug
+ AnyCPU
+ {8C625DE3-0067-454A-AF2C-EFD672EEB31A}
+ Library
+ Properties
+ Microsoft.Azure.Commands.TestFx
+ Microsoft.Azure.PowerShell.TestFx
+ v4.5.2
+ 512
+ ..\..\
+ true
+ e5bda5ba
+ $(ProjectDir)obj\$(Configuration)\net452
+ $(BaseIntermediateOutputPath)
+ NU5111
+ false
+
+
+ true
+ full
+ false
+ $(ProjectDir)..\..\artifacts\$(Configuration)\net452
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ $(ProjectDir)..\..\artifacts\$(Configuration)\net452
+ TRACE;SIGN
+ true
+ ..\MSSharedLibKey.snk
+ true
+ true
+ false
+ true
+ pdbonly
+
+
+
+
+
+
+
+
+
+
+
+ {70527617-7598-4aef-b5bd-db9186b8184b}
+ Authentication.Abstractions
+
+
+ {d3804b64-c0d3-48f8-82ec-1f632f833c9e}
+ Authentication
+
+
+ {269ACF73-0A34-42DC-AB9C-4B15931A489D}
+ Graph.Rbac
+
+
+ {69C2EB6B-CD63-480A-89A0-C489706E9299}
+ Authentication.ResourceManager
+
+
+ {3436a126-edc9-4060-8952-9a1be34cdd95}
+ ScenarioTest.ResourceManager
+
+
+
+
\ No newline at end of file
diff --git a/src/TestFx/TestFx.nuspec b/src/TestFx/TestFx.nuspec
new file mode 100644
index 0000000000..0a52095e43
--- /dev/null
+++ b/src/TestFx/TestFx.nuspec
@@ -0,0 +1,16 @@
+
+
+
+ Microsoft.Azure.PowerShell.TestFx
+ 1.0.0-preview
+ Microsoft Azure PowerShell TestFx
+ Microsoft Corporation
+ Microsoft Corporation
+ false
+ https://aka.ms/azps-common-license
+ https://github.com/Azure/azure-powershell-common
+ Microsoft Azure PowerShell TestFx library. Only for use with the Azure PowerShell runtime. Not intended for general development use.
+ Copyright © Microsoft Corporation
+ azure powershell testfx
+
+
\ No newline at end of file
diff --git a/src/TestFx/TestManager.cs b/src/TestFx/TestManager.cs
new file mode 100644
index 0000000000..74a9e04d20
--- /dev/null
+++ b/src/TestFx/TestManager.cs
@@ -0,0 +1,296 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using Microsoft.Azure.Commands.Common.Authentication;
+using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
+using Microsoft.Azure.Commands.Common.Authentication.Models;
+using Microsoft.Azure.Commands.ResourceManager.Common;
+using Microsoft.Azure.ServiceManagemenet.Common.Models;
+using Microsoft.Azure.Test.HttpRecorder;
+using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
+using Microsoft.WindowsAzure.Commands.ScenarioTest;
+using Xunit.Abstractions;
+
+namespace Microsoft.Azure.Commands.TestFx
+{
+ public delegate IRecordMatcher RecordMatcherDelegate (bool ignoreResourcesClient, Dictionary resourceProviders, Dictionary userAgentsToIgnore);
+
+ public class TestManager : ITestRunnerFactory, ITestRunner
+ {
+ private readonly string _callingClassName;
+ private string _projectSubfolderForTestsName = null;
+ private string _newPsScriptFilename = null;
+ private Dictionary _userAgentsToIgnore;
+ protected EnvironmentSetupHelper Helper;
+ protected readonly List RmModules;
+ protected readonly List CommonPsScripts = new List();
+
+ protected RecordMatcherDelegate RecordMatcher { get; set; }
+
+ protected XunitTracingInterceptor Logger { get; set; }
+
+ ///
+ /// Factory method
+ ///
+ ///
+ ///
+ ///
+ public static ITestRunnerFactory CreateInstance(ITestOutputHelper output, [CallerFilePath] string callerFilePath = null)
+ {
+ var callingClassName = string.IsNullOrEmpty(callerFilePath)
+ ? null
+ : Path.GetFileNameWithoutExtension(callerFilePath);
+ return new TestManager(callingClassName).WithTestOutputHelper(output);
+ }
+
+ ///
+ /// ctor
+ ///
+ ///
+ protected TestManager(string callingClassName)
+ {
+ Helper = new EnvironmentSetupHelper();
+ _callingClassName = callingClassName;
+
+ RmModules = new List
+ {
+ Helper.RMProfileModule,
+ Helper.RMResourceModule,
+ };
+
+ RecordMatcher = (ignoreResourcesClient, resourceProviders, userAgentsToIgnore) =>
+ new PermissiveRecordMatcherWithApiExclusion(ignoreResourcesClient, resourceProviders, userAgentsToIgnore);
+ }
+
+ #region Builder impl
+
+ ///
+ /// Sets a name of the subfolder where a test project keeps tests
+ ///
+ ///
+ /// self
+ public ITestRunnerFactory WithProjectSubfolderForTests(string folderName)
+ {
+ _projectSubfolderForTestsName = folderName ?? "ScenarioTests";
+ return this;
+ }
+
+ ///
+ /// Add helper scripts
+ ///
+ ///
+ /// self
+ public ITestRunnerFactory WithCommonPsScripts(string[] psScriptList)
+ {
+ CommonPsScripts.AddRange(psScriptList);
+ return this;
+ }
+
+ ///
+ /// Overrided default script name, which by convension is the cs test class name with ps1 extension.
+ ///
+ ///
+ /// self
+ public ITestRunnerFactory WithNewPsScriptFilename(string psScriptName)
+ {
+ _newPsScriptFilename = psScriptName;
+ return this;
+ }
+
+ ///
+ /// Adds extra RM modules in addition to the RMProfileModule and RMResourceModule,
+ /// witch are added in the constructor.
+ ///
+ ///
+ ///
+ public ITestRunnerFactory WithExtraRmModules(Func buildModuleList)
+ {
+ var moduleList = buildModuleList(Helper);
+ RmModules.AddRange(moduleList);
+ return this;
+ }
+
+ ///
+ /// Clears default RM modules list and sets a brand new
+ ///
+ ///
+ ///
+ public ITestRunnerFactory WithNewRmModules(Func buildModuleList)
+ {
+ RmModules.Clear();
+ var moduleList = buildModuleList(Helper);
+ RmModules.AddRange(moduleList);
+ return this;
+ }
+
+ ///
+ /// Sets a new HttpMockServer.Matcher implementation. By defauls it's PermissiveRecordMatcherWithApiExclusion
+ ///
+ /// delegate
+ /// self
+ public ITestRunnerFactory WithRecordMatcher(RecordMatcherDelegate recordMatcher)
+ {
+ RecordMatcher = recordMatcher;
+ return this;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ /// Dictionary to store pairs: {user agent name, version-api to ignore}.
+ /// Initial pair is {"Microsoft.Azure.Management.Resources.ResourceManagementClient", "2016-02-01"}
+ ///
+ /// self
+ public ITestRunnerFactory WithExtraUserAgentsToIgnore(Dictionary userAgentsToIgnore)
+ {
+ _userAgentsToIgnore = userAgentsToIgnore;
+ return this;
+ }
+
+ public ITestRunnerFactory WithTestOutputHelper(ITestOutputHelper output)
+ {
+ Logger = new XunitTracingInterceptor(output);
+ XunitTracingInterceptor.AddToContext(Logger);
+ Helper.TracingInterceptor = Logger;
+ return this;
+ }
+
+ public ITestRunner Build()
+ {
+ SetupSessionAndProfile();
+ SetupMockServerMatcher();
+ HttpMockServer.RecordsDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SessionRecords");
+ Helper.SetupModules(AzureModule.AzureResourceManager, BuildModulesList());
+ return this;
+ }
+
+ public void RunTestScript(params string[] scripts)
+ {
+ var sf = new StackTrace().GetFrame(1);
+ var className = sf.GetMethod().ReflectedType?.ToString();
+ var methodName = sf.GetMethod().Name;
+
+ using (var mockContext = MockContext.Start(className, methodName))
+ {
+ AzureSession.Instance.ClientFactory = new TestClientFactory(mockContext);
+ Helper.SetupEnvironment(AzureModule.AzureResourceManager);
+ SetupAzureContext();
+ Helper.RunPowerShellTest(scripts);
+ }
+ }
+
+ #endregion
+
+ #region Helpers
+
+ protected string[] BuildModulesList()
+ {
+ if (string.IsNullOrEmpty(_callingClassName)
+ && string.IsNullOrEmpty(_newPsScriptFilename))
+ throw new ArgumentNullException($"Both {nameof(_callingClassName)} and {nameof(_newPsScriptFilename)} are null");
+
+ var allScripts = CommonPsScripts;
+ allScripts.Add(_newPsScriptFilename ?? $"{_callingClassName}.ps1");
+
+ var allScriptsWithPath = _projectSubfolderForTestsName == null
+ ? allScripts
+ : allScripts.Select(s => Path.Combine(_projectSubfolderForTestsName, s));
+
+ var allModules = RmModules;
+ allModules.AddRange(allScriptsWithPath);
+
+ return allModules.ToArray();
+ }
+
+ protected void SetupSessionAndProfile()
+ {
+ AzureSessionInitializer.InitializeAzureSession();
+ AzureSession.Instance.ARMContextSaveMode = ContextSaveMode.Process;
+ ResourceManagerProfileProvider.InitializeResourceManagerProfile();
+ if (!(AzureSession.Instance?.DataStore is MemoryDataStore))
+ {
+ AzureSession.Instance.DataStore = new MemoryDataStore();
+ }
+ }
+
+ protected void SetupAzureContext()
+ {
+ const string tenantIdKey = "TenantId";
+ const string domainKey = "Domain";
+ const string subscriptionIdKey = "SubscriptionId";
+ const string undefined = "Undefined";
+ var zeroGuild = Guid.Empty.ToString();
+
+ string tenantId = null;
+ string userDomain = null;
+ string subscriptionId = null;
+
+ if (HttpMockServer.Mode == HttpRecorderMode.Record)
+ {
+ var environment = TestEnvironmentFactory.GetTestEnvironment();
+ tenantId = environment.Tenant;
+ userDomain = string.IsNullOrEmpty(environment.UserName)
+ ? string.Empty
+ : environment.UserName.Split(new[] { "@" }, StringSplitOptions.RemoveEmptyEntries).Last();
+
+ subscriptionId = environment.SubscriptionId;
+ }
+ else if (HttpMockServer.Mode == HttpRecorderMode.Playback)
+ {
+ tenantId = HttpMockServer.Variables.ContainsKey(tenantIdKey)
+ ? HttpMockServer.Variables[tenantIdKey]
+ : zeroGuild;
+ userDomain = HttpMockServer.Variables.ContainsKey(domainKey)
+ ? HttpMockServer.Variables[domainKey]
+ : "testdomain.onmicrosoft.com";
+ subscriptionId = HttpMockServer.Variables.ContainsKey(subscriptionIdKey)
+ ? HttpMockServer.Variables[subscriptionIdKey]
+ : zeroGuild;
+ }
+
+ AzureRmProfileProvider.Instance.Profile.DefaultContext.Tenant.Id = tenantId ?? undefined;
+ AzureRmProfileProvider.Instance.Profile.DefaultContext.Tenant.Directory = userDomain ?? undefined;
+ AzureRmProfileProvider.Instance.Profile.DefaultContext.Subscription.Id = subscriptionId ?? undefined;
+ }
+
+ protected void SetupMockServerMatcher()
+ {
+ var resourceProviders = new Dictionary
+ {
+ {"Microsoft.Resources", null},
+ {"Microsoft.Features", null},
+ {"Microsoft.Authorization", null},
+ {"Providers.Test", null},
+ };
+
+ var userAgentsToIgnore = new Dictionary
+ {
+ {"Microsoft.Azure.Management.Resources.ResourceManagementClient", "2016-02-01"},
+ };
+
+ _userAgentsToIgnore?.Keys.ForEach(k=> userAgentsToIgnore.Add(k, _userAgentsToIgnore[k]));
+
+ HttpMockServer.Matcher = RecordMatcher(true, resourceProviders, userAgentsToIgnore);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/TestFx/TestRunnerBase.cs b/src/TestFx/TestRunnerBase.cs
new file mode 100644
index 0000000000..f1a6fa44c1
--- /dev/null
+++ b/src/TestFx/TestRunnerBase.cs
@@ -0,0 +1,31 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Xunit.Abstractions;
+
+namespace Microsoft.Azure.Commands.TestFx
+{
+ public class TestRunnerBase
+ {
+ protected readonly ITestRunner TestRunner;
+
+ protected TestRunnerBase(ITestOutputHelper output)
+ {
+ TestRunner = TestManager
+ .CreateInstance(output)
+ .WithNewPsScriptFilename($"{GetType().Name}.ps1")
+ .Build();
+ }
+ }
+}