[Feature] Add tests for experimental feature work

This commit is contained in:
Dongbo Wang
2018-07-06 13:28:20 -07:00
parent 3c3ddeb127
commit d2e9151fff
8 changed files with 964 additions and 2 deletions
@@ -1481,7 +1481,7 @@ namespace System.Management.Automation.Language
private static RuntimeDefinedParameter GetRuntimeDefinedParameter(ParameterAst parameterAst, ref bool customParameterSet, ref bool usesCmdletBinding)
{
List<Attribute> attributes = new List<Attribute>(parameterAst.Attributes.Count);
var attributes = new List<Attribute>(parameterAst.Attributes.Count);
bool hasParameterAttribute = false;
bool hasEnabledParamAttribute = false;
bool hasSeenExpAttribute = false;
@@ -1509,7 +1509,7 @@ namespace System.Management.Automation.Language
usesCmdletBinding = true;
if (paramAttribute.Position != int.MinValue ||
!paramAttribute.ParameterSetName.Equals(ParameterAttribute.AllParameterSets,
StringComparison.OrdinalIgnoreCase))
StringComparison.OrdinalIgnoreCase))
{
customParameterSet = true;
}
@@ -70,6 +70,18 @@ Describe "Type accelerators" -Tags "CI" {
Accelerator = 'DscResource'
Type = [System.Management.Automation.DscResourceAttribute]
}
@{
Accelerator = 'ExperimentAction'
Type = [System.Management.Automation.ExperimentAction]
}
@{
Accelerator = 'Experimental'
Type = [System.Management.Automation.ExperimentalAttribute]
}
@{
Accelerator = 'ExperimentalFeature'
Type = [System.Management.Automation.ExperimentalFeature]
}
@{
Accelerator = 'float'
Type = [System.Single]
@@ -258,6 +258,7 @@ Describe "Verify approved aliases list" -Tags "CI" {
"Cmdlet", "Get-EventLog", , $($FullCLR )
"Cmdlet", "Get-EventSubscriber", , $($FullCLR -or $CoreWindows -or $CoreUnix)
"Cmdlet", "Get-ExecutionPolicy", , $($FullCLR -or $CoreWindows -or $CoreUnix)
"Cmdlet", "Get-ExperimentalFeature", , $( $CoreWindows -or $CoreUnix)
"Cmdlet", "Get-FileHash", , $( $CoreWindows -or $CoreUnix)
"Cmdlet", "Get-FormatData", , $($FullCLR -or $CoreWindows -or $CoreUnix)
"Cmdlet", "Get-Help", , $($FullCLR -or $CoreWindows -or $CoreUnix)
@@ -0,0 +1,367 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
Describe "Experimental Feature Basic Tests - Feature-Disabled" -tags "CI" {
BeforeAll {
$skipTest = $EnabledExperimentalFeatures.Contains('ExpTest.FeatureOne')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'ExpTest.FeatureOne' to be disabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
} else {
$TestModule = Join-Path $PSScriptRoot "assets" "ExpTest"
$AssemblyPath = Join-Path $TestModule "ExpTest.dll"
if (-not (Test-Path $AssemblyPath)) {
$SourcePath = Join-Path $TestModule "ExpTest.cs"
Add-Type -Path $SourcePath -OutputType Library -OutputAssembly $AssemblyPath
}
$moduleInfo = Import-Module $TestModule -PassThru
}
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
} else {
Remove-Module -ModuleInfo $moduleInfo -Force -ErrorAction SilentlyContinue
}
}
It "No experimental features is enabled" {
$EnabledExperimentalFeatures.Count | Should -Be 0
}
It "Replace existing command <Name> - version one should be shown" -TestCases @(
@{ Name = "Invoke-AzureFunction"; CommandType = "Function" }
@{ Name = "Invoke-AzureFunctionCSharp"; CommandType = "Cmdlet" }
) {
param($Name, $CommandType)
$command = Get-Command $Name
$command.CommandType | Should -Be $CommandType
$command.Source | Should -BeExactly $moduleInfo.Name
& $Name -Token "Token" -Command "Command" | Should -BeExactly "Invoke-AzureFunction Version ONE"
if ($CommandType -eq "Function") {
$expectedErrorId = "CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand"
{ Get-Command "Invoke-AzureFunctionV2" -ErrorAction Stop } | Should -Throw -ErrorId $expectedErrorId
{ & $moduleInfo { Get-Command "Invoke-AzureFunctionV2" -ErrorAction Stop } } | Should -Throw -ErrorId $expectedErrorId
}
}
It "Experimental parameter set - '<Name>' should NOT have '-SwitchOne' and '-SwitchTwo'" -TestCases @(
@{ Name = "Get-GreetingMessage"; CommandType = "Function" }
@{ Name = "Get-GreetingMessageCSharp"; CommandType = "Cmdlet" }
) {
param($Name, $CommandType)
$command = Get-Command $Name
$command.CommandType | Should -Be $CommandType
## 11 common parameters + '-Name'
$command.Parameters.Count | Should -Be 12
& $Name -Name Joe | Should -BeExactly "Hello World Joe."
}
It "Experimental parameter set - '<Name>' should NOT have 'WebSocket' parameter set" -TestCases @(
@{ Name = "Invoke-MyCommand"; CommandType = "Function" }
@{ Name = "Invoke-MyCommandCSharp"; CommandType = "Cmdlet" }
) {
param($Name, $CommandType)
$command = Get-Command $Name
$command.CommandType | Should -Be $CommandType
## 11 common parameters + '-UserName', '-ComputerName', '-ConfigurationName', '-VMName', '-Port', '-ThrottleLimit' and '-Command'
$command.Parameters.Count | Should -Be 18
$command.ParameterSets.Count | Should -Be 2
$command.Parameters["UserName"].ParameterSets.Count | Should -Be 1
$command.Parameters["UserName"].ParameterSets.ContainsKey("ComputerSet") | Should -Be $true
$command.Parameters["ComputerName"].ParameterSets.Count | Should -Be 1
$command.Parameters["ComputerName"].ParameterSets.ContainsKey("ComputerSet") | Should -Be $true
$command.Parameters["ConfigurationName"].ParameterSets.Count | Should -Be 1
$command.Parameters["ConfigurationName"].ParameterSets.ContainsKey("ComputerSet") | Should -Be $true
$command.Parameters["VMName"].ParameterSets.Count | Should -Be 1
$command.Parameters["VMName"].ParameterSets.ContainsKey("VMSet") | Should -Be $true
$command.Parameters["Port"].ParameterSets.Count | Should -Be 1
$command.Parameters["Port"].ParameterSets.ContainsKey("VMSet") | Should -Be $true
$command.Parameters["ThrottleLimit"].ParameterSets.Count | Should -Be 1
$command.Parameters["ThrottleLimit"].ParameterSets.ContainsKey("__AllParameterSets") | Should -Be $true
$command.Parameters["Command"].ParameterSets.Count | Should -Be 1
$command.Parameters["Command"].ParameterSets.ContainsKey("__AllParameterSets") | Should -Be $true
## 11 common parameters + '-UserName', '-ComputerName', '-ConfigurationName', '-ThrottleLimit' and '-Command'
$command.ParameterSets[0].Name | Should -BeExactly "ComputerSet"
$command.ParameterSets[0].Parameters.Count | Should -Be 16
## 11 common parameters + '-VMName', '-Port', '-ThrottleLimit' and '-Command'
$command.ParameterSets[1].Name | Should -BeExactly "VMSet"
$command.ParameterSets[1].Parameters.Count | Should -Be 15
& $Name -UserName "user" -ComputerName "localhost" -ConfigurationName "config" | Should -BeExactly "Invoke-MyCommand with ComputerSet"
& $Name -VMName "VM" -Port "80" | Should -BeExactly "Invoke-MyCommand with VMSet"
}
It "Experimental parameter set - '<Name>' should have '-SessionName' only" -TestCases @(
@{ Name = "Test-MyRemoting"; CommandType = "Function" }
@{ Name = "Test-MyRemotingCSharp"; CommandType = "Cmdlet" }
) {
param($Name, $CommandType)
$command = Get-Command $Name
$command.CommandType | Should -Be $CommandType
## 11 common parameters + '-SessionName'
$command.Parameters.Count | Should -Be 12
$command.Parameters["SessionName"].ParameterType.FullName | Should -BeExactly "System.String"
$command.Parameters.ContainsKey("ComputerName") | Should -Be $false
}
It "Use 'Experimental' attribute directly on parameters - '<Name>'" -TestCases @(
@{ Name = "Save-MyFile"; CommandType = "Function" }
@{ Name = "Save-MyFileCSharp"; CommandType = "Cmdlet" }
) {
param($Name, $CommandType)
$command = Get-Command $Name
$command.CommandType | Should -Be $CommandType
## 11 common parameters + '-ByUrl', '-ByRadio', '-FileName', '-Configuration'
$command.Parameters.Count | Should -Be 15
$command.ParameterSets.Count | Should -Be 2
$command.Parameters["ByUrl"].ParameterSets.Count | Should -Be 1
$command.Parameters["ByUrl"].ParameterSets.ContainsKey("UrlSet") | Should -Be $true
$command.Parameters["ByRadio"].ParameterSets.Count | Should -Be 1
$command.Parameters["ByRadio"].ParameterSets.ContainsKey("RadioSet") | Should -Be $true
$command.Parameters["Configuration"].ParameterSets.Count | Should -Be 2
$command.Parameters["Configuration"].ParameterSets.ContainsKey("UrlSet") | Should -Be $true
$command.Parameters["Configuration"].ParameterSets.ContainsKey("RadioSet") | Should -Be $true
$command.Parameters["FileName"].ParameterSets.Count | Should -Be 1
$command.Parameters["FileName"].ParameterSets.ContainsKey("__AllParameterSets") | Should -Be $true
$command.Parameters.ContainsKey("Destination") | Should -Be $false
}
It "Dynamic parameters - <CommandType>-<Name>" -TestCases @(
@{ Name = "Test-MyDynamicParamOne"; CommandType = "Function" }
@{ Name = "Test-MyDynamicParamOneCSharp"; CommandType = "Cmdlet" }
@{ Name = "Test-MyDynamicParamTwo"; CommandType = "Function" }
@{ Name = "Test-MyDynamicParamTwoCSharp"; CommandType = "Cmdlet" }
) {
param($Name, $CommandType)
$command = Get-Command $Name
$command.CommandType | Should -Be $CommandType
## 11 common parameters + '-Name' (dynamic parameters are not triggered)
$command.Parameters.Count | Should -Be 12
$command.Parameters["Name"] | Should -Not -BeNullOrEmpty
$command = Get-Command $Name -ArgumentList "Joe"
## 11 common parameters + '-Name' and '-ConfigName' (dynamic parameters are triggered)
$command.Parameters.Count | Should -Be 13
$command.Parameters["ConfigName"].Attributes.Count | Should -Be 2
$command.Parameters["ConfigName"].Attributes[0] | Should -BeOfType [parameter]
$command.Parameters["ConfigName"].Attributes[1] | Should -BeOfType [ValidateNotNullOrEmpty]
$command.Parameters.ContainsKey("ConfigFile") | Should -Be $false
}
}
Describe "Experimental Feature Basic Tests - Feature-Enabled" -Tag "CI" {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('ExpTest.FeatureOne')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'ExpTest.FeatureOne' to be enabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
} else {
$TestModule = Join-Path $PSScriptRoot "assets" "ExpTest"
$AssemblyPath = Join-Path $TestModule "ExpTest.dll"
if (-not (Test-Path $AssemblyPath)) {
$SourcePath = Join-Path $TestModule "ExpTest.cs"
Add-Type -Path $SourcePath -OutputType Library -OutputAssembly $AssemblyPath
}
$moduleInfo = Import-Module $TestModule -PassThru
}
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
} else {
Remove-Module -ModuleInfo $moduleInfo -Force -ErrorAction SilentlyContinue
}
}
It "Experimental feature 'ExpTest.FeatureOne' should be enabled" {
$EnabledExperimentalFeatures.Count | Should -Be 1
$EnabledExperimentalFeatures -contains "ExpTest.FeatureOne" | Should -Be $true
}
It "Replace existing command <Name> - version two should be shown" -TestCases @(
@{ Name = "Invoke-AzureFunction"; CommandType = "Alias" }
@{ Name = "Invoke-AzureFunctionCSharp"; CommandType = "Cmdlet" }
) {
param($Name, $CommandType)
$command = Get-Command $Name
$command.CommandType | Should -Be $CommandType
$command.Source | Should -BeExactly $moduleInfo.Name
& $Name -Token "Token" -Command "Command" | Should -BeExactly "Invoke-AzureFunction Version TWO"
if ($CommandType -eq "Alias") {
$command.Definition | Should -Be "Invoke-AzureFunctionV2"
$expectedErrorId = "CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand"
{ Get-Command "Invoke-AzureFunction" -CommandType Function -ErrorAction Stop } | Should -Throw -ErrorId $expectedErrorId
{ & $moduleInfo { Get-Command "Invoke-AzureFunction" -CommandType Function -ErrorAction Stop } } | Should -Throw -ErrorId $expectedErrorId
}
}
It "Experimental parameter set - '<Name>' should have '-SwitchOne' and '-SwitchTwo'" -TestCases @(
@{ Name = "Get-GreetingMessage"; CommandType = "Function" }
@{ Name = "Get-GreetingMessageCSharp"; CommandType = "Cmdlet" }
) {
param($Name, $CommandType)
$command = Get-Command $Name
$command.CommandType | Should -Be $CommandType
## 11 common parameters + '-Name' + '-SwitchOne' + '-SwitchTwo'
$command.Parameters.Count | Should -Be 14
$command.ParameterSets.Count | Should -Be 3
& $Name -Name Joe | Should -BeExactly "Hello World Joe."
& $Name -Name Joe -SwitchOne | Should -BeExactly "Hello World Joe.-SwitchOne is on."
& $Name -Name Joe -SwitchTwo | Should -BeExactly "Hello World Joe.-SwitchTwo is on."
}
It "Experimental parameter set - '<Name>' should have 'WebSocket' parameter set" -TestCases @(
@{ Name = "Invoke-MyCommand"; CommandType = "Function" }
@{ Name = "Invoke-MyCommandCSharp"; CommandType = "Cmdlet" }
) {
param($Name, $CommandType)
$command = Get-Command $Name
$command.CommandType | Should -Be $CommandType
## 11 common parameters + '-UserName', '-ComputerName', '-ConfigurationName', '-VMName', '-Port',
## '-Token', '-WebSocketUrl', '-ThrottleLimit' and '-Command'
$command.Parameters.Count | Should -Be 20
$command.ParameterSets.Count | Should -Be 3
$command.Parameters["UserName"].ParameterSets.Count | Should -Be 1
$command.Parameters["UserName"].ParameterSets.ContainsKey("ComputerSet") | Should -Be $true
$command.Parameters["ComputerName"].ParameterSets.Count | Should -Be 1
$command.Parameters["ComputerName"].ParameterSets.ContainsKey("ComputerSet") | Should -Be $true
$command.Parameters["VMName"].ParameterSets.Count | Should -Be 1
$command.Parameters["VMName"].ParameterSets.ContainsKey("VMSet") | Should -Be $true
$command.Parameters["Token"].ParameterSets.Count | Should -Be 1
$command.Parameters["Token"].ParameterSets.ContainsKey("WebSocketSet") | Should -Be $true
$command.Parameters["WebSocketUrl"].ParameterSets.Count | Should -Be 1
$command.Parameters["WebSocketUrl"].ParameterSets.ContainsKey("WebSocketSet") | Should -Be $true
$command.Parameters["ConfigurationName"].ParameterSets.Count | Should -Be 2
$command.Parameters["ConfigurationName"].ParameterSets.ContainsKey("ComputerSet") | Should -Be $true
$command.Parameters["ConfigurationName"].ParameterSets.ContainsKey("WebSocketSet") | Should -Be $true
$command.Parameters["Port"].ParameterSets.Count | Should -Be 2
$command.Parameters["Port"].ParameterSets.ContainsKey("VMSet") | Should -Be $true
$command.Parameters["Port"].ParameterSets.ContainsKey("WebSocketSet") | Should -Be $true
$command.Parameters["ThrottleLimit"].ParameterSets.Count | Should -Be 1
$command.Parameters["ThrottleLimit"].ParameterSets.ContainsKey("__AllParameterSets") | Should -Be $true
$command.Parameters["Command"].ParameterSets.Count | Should -Be 1
$command.Parameters["Command"].ParameterSets.ContainsKey("__AllParameterSets") | Should -Be $true
## 11 common parameters + '-UserName', '-ComputerName', '-ConfigurationName', '-ThrottleLimit' and '-Command'
$command.ParameterSets[0].Name | Should -BeExactly "ComputerSet"
$command.ParameterSets[0].Parameters.Count | Should -Be 16
## 11 common parameters + '-VMName', '-Port', '-ThrottleLimit' and '-Command'
$command.ParameterSets[1].Name | Should -BeExactly "VMSet"
$command.ParameterSets[1].Parameters.Count | Should -Be 15
## 11 common parameters + '-Token', '-WebSocketUrl', '-ConfigurationName', '-Port', '-ThrottleLimit', '-Command'
$command.ParameterSets[2].Name | Should -BeExactly "WebSocketSet"
$command.ParameterSets[2].Parameters.Count | Should -Be 17
& $Name -UserName "user" -ComputerName "localhost" | Should -BeExactly "Invoke-MyCommand with ComputerSet"
& $Name -UserName "user" -ComputerName "localhost" -ConfigurationName "config" | Should -BeExactly "Invoke-MyCommand with ComputerSet"
& $Name -VMName "VM" | Should -BeExactly "Invoke-MyCommand with VMSet"
& $Name -VMName "VM" -Port "80" | Should -BeExactly "Invoke-MyCommand with VMSet"
& $Name -Token "token" -WebSocketUrl 'url' | Should -BeExactly "Invoke-MyCommand with WebSocketSet"
& $Name -Token "token" -WebSocketUrl 'url' -ConfigurationName 'config' -Port 80 | Should -BeExactly "Invoke-MyCommand with WebSocketSet"
}
It "Experimental parameter set - '<Name>' should have '-ComputerName' only" -TestCases @(
@{ Name = "Test-MyRemoting"; CommandType = "Function" }
@{ Name = "Test-MyRemotingCSharp"; CommandType = "Cmdlet" }
) {
param($Name, $CommandType)
$command = Get-Command $Name
$command.CommandType | Should -Be $CommandType
## 11 common parameters + '-ComputerName'
$command.Parameters.Count | Should -Be 12
$command.Parameters["ComputerName"].ParameterType.FullName | Should -BeExactly "System.String"
$command.Parameters.ContainsKey("SessionName") | Should -Be $false
}
It "Use 'Experimental' attribute directly on parameters - '<Name>'" -TestCases @(
@{ Name = "Save-MyFile"; CommandType = "Function" }
@{ Name = "Save-MyFileCSharp"; CommandType = "Cmdlet" }
) {
param($Name, $CommandType)
$command = Get-Command $Name
$command.CommandType | Should -Be $CommandType
## 11 common parameters + '-ByUrl', '-ByRadio', '-FileName', '-Destination'
$command.Parameters.Count | Should -Be 15
$command.ParameterSets.Count | Should -Be 2
$command.Parameters["ByUrl"].ParameterSets.Count | Should -Be 1
$command.Parameters["ByUrl"].ParameterSets.ContainsKey("UrlSet") | Should -Be $true
$command.Parameters["ByRadio"].ParameterSets.Count | Should -Be 1
$command.Parameters["ByRadio"].ParameterSets.ContainsKey("RadioSet") | Should -Be $true
$command.Parameters["Destination"].ParameterSets.Count | Should -Be 1
$command.Parameters["Destination"].ParameterSets.ContainsKey("__AllParameterSets") | Should -Be $true
$command.Parameters["FileName"].ParameterSets.Count | Should -Be 1
$command.Parameters["FileName"].ParameterSets.ContainsKey("__AllParameterSets") | Should -Be $true
$command.Parameters.ContainsKey("Configuration") | Should -Be $false
}
It "Dynamic parameters - <CommandType>-<Name>" -TestCases @(
@{ Name = "Test-MyDynamicParamOne"; CommandType = "Function" }
@{ Name = "Test-MyDynamicParamOneCSharp"; CommandType = "Cmdlet" }
@{ Name = "Test-MyDynamicParamTwo"; CommandType = "Function" }
@{ Name = "Test-MyDynamicParamTwoCSharp"; CommandType = "Cmdlet" }
) {
param($Name, $CommandType)
$command = Get-Command $Name
$command.CommandType | Should -Be $CommandType
## 11 common parameters + '-Name' (dynamic parameters are not triggered)
$command.Parameters.Count | Should -Be 12
$command.Parameters["Name"] | Should -Not -BeNullOrEmpty
$command = Get-Command $Name -ArgumentList "Joe"
## 11 common parameters + '-Name' and '-ConfigFile' (dynamic parameters are triggered)
$command.Parameters.Count | Should -Be 13
$command.Parameters["ConfigFile"].Attributes.Count | Should -Be 2
$command.Parameters["ConfigFile"].Attributes[0] | Should -BeOfType [parameter]
$command.Parameters["ConfigFile"].Attributes[1] | Should -BeOfType [ValidateNotNullOrEmpty]
$command.Parameters.ContainsKey("ConfigName") | Should -Be $false
}
}
@@ -0,0 +1,117 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
Describe "Get-ExperimentalFeature basic tests - Feature-Disabled" -tags "CI" {
BeforeAll {
$skipTest = $EnabledExperimentalFeatures.Contains('ExpTest.FeatureOne')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'ExpTest.FeatureOne' to be disabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
} else {
Remove-Module -Name ExpTest -Force -ErrorAction SilentlyContinue
$testModulePath = Join-Path -Path $PSScriptRoot -ChildPath "assets"
$testModuleManifestPath = Join-Path -Path $testModulePath "ExpTest" "ExpTest.psd1"
$originalModulePath = $env:PSModulePath
$env:PSModulePath = $testModulePath
}
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
} else {
$env:PSModulePath = $originalModulePath
}
}
It "'Get-ExperimentalFeature' should only return enabled features" {
$EnabledExperimentalFeatures.Count | Should -Be 0
Get-ExperimentalFeature | Should -BeNullOrEmpty
}
It "'Get-ExperimentalFeature -ListAvailable' should return all available features from module path" {
$features = Get-ExperimentalFeature "ExpTest*" -ListAvailable
$features | Should -Not -BeNullOrEmpty
$features[0].Name | Should -BeExactly "ExpTest.FeatureOne"
$features[0].Enabled | Should -Be $false
$features[0].Source | Should -BeExactly $testModuleManifestPath
$features[1].Name | Should -BeExactly "ExpTest.FeatureTwo"
$features[1].Enabled | Should -Be $false
$features[1].Source | Should -BeExactly $testModuleManifestPath
}
It "'Get-ExperimentalFeature -ListAvailable' pipeline input" {
$features = "ExpTest.FeatureOne", "ExpTest.FeatureTwo" | Get-ExperimentalFeature -ListAvailable
$features | Should -Not -BeNullOrEmpty
$features[0].Name | Should -BeExactly "ExpTest.FeatureOne"
$features[0].Enabled | Should -Be $false
$features[0].Source | Should -BeExactly $testModuleManifestPath
$features[1].Name | Should -BeExactly "ExpTest.FeatureTwo"
$features[1].Enabled | Should -Be $false
$features[1].Source | Should -BeExactly $testModuleManifestPath
}
}
Describe "Get-ExperimentalFeature basic tests - Feature-Enabled" -tags "CI" {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('ExpTest.FeatureOne')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'ExpTest.FeatureOne' to be enabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
} else {
Remove-Module -Name ExpTest -Force -ErrorAction SilentlyContinue
$testModulePath = Join-Path -Path $PSScriptRoot -ChildPath "assets"
$testModuleManifestPath = Join-Path -Path $testModulePath "ExpTest" "ExpTest.psd1"
$originalModulePath = $env:PSModulePath
$env:PSModulePath = $testModulePath
}
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
} else {
$env:PSModulePath = $originalModulePath
}
}
It "'Get-ExperimentalFeature' should return enabled features 'ExpTest.FeatureOne'" {
$EnabledExperimentalFeatures.Count | Should -Be 1
$feature = Get-ExperimentalFeature "ExpTest.FeatureOne"
$feature | Should -Not -BeNullOrEmpty
$feature.Enabled | Should -Be $true
$feature.Source | Should -BeExactly $testModuleManifestPath
}
It "'Get-ExperimentalFeature -ListAvailable' should return all available features from module path" {
$features = Get-ExperimentalFeature "ExpTest*" -ListAvailable
$features | Should -Not -BeNullOrEmpty
$features[0].Name | Should -BeExactly "ExpTest.FeatureOne"
$features[0].Enabled | Should -Be $true
$features[0].Source | Should -BeExactly $testModuleManifestPath
$features[1].Name | Should -BeExactly "ExpTest.FeatureTwo"
$features[1].Enabled | Should -Be $false
$features[1].Source | Should -BeExactly $testModuleManifestPath
}
It "'Get-ExperimentalFeature -ListAvailable' pipeline input" {
$features = "ExpTest.FeatureOne", "ExpTest.FeatureTwo" | Get-ExperimentalFeature -ListAvailable
$features | Should -Not -BeNullOrEmpty
$features[0].Name | Should -BeExactly "ExpTest.FeatureOne"
$features[0].Enabled | Should -Be $true
$features[0].Source | Should -BeExactly $testModuleManifestPath
$features[1].Name | Should -BeExactly "ExpTest.FeatureTwo"
$features[1].Enabled | Should -Be $false
$features[1].Source | Should -BeExactly $testModuleManifestPath
}
}
@@ -0,0 +1,216 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Management.Automation;
namespace ExperimentalFeatureTest
{
#region "Replace existing cmdlet"
[Experimental("ExpTest.FeatureOne", ExperimentAction.Hide)]
[Cmdlet("Invoke", "AzureFunctionCSharp")]
public class InvokeAzureFunctionCommand : PSCmdlet
{
[Parameter]
public string Token { get; set; }
[Parameter]
public string Command { get; set; }
protected override void EndProcessing()
{
WriteObject("Invoke-AzureFunction Version ONE");
}
}
[Experimental("ExpTest.FeatureOne", ExperimentAction.Show)]
[Cmdlet("Invoke", "AzureFunctionCSharp")]
public class InvokeAzureFunctionCommandV2 : PSCmdlet
{
[Parameter(Mandatory = true)]
public string Token { get; set; }
[Parameter(Mandatory = true)]
public string Command { get; set; }
protected override void EndProcessing()
{
WriteObject("Invoke-AzureFunction Version TWO");
}
}
#endregion
#region "Make parameter set experimental"
[Cmdlet("Get", "GreetingMessageCSharp", DefaultParameterSetName = "Default")]
public class GetGreetingMessageCommand : PSCmdlet
{
[Parameter(Mandatory = true)]
public string Name { get; set; }
[Parameter("ExpTest.FeatureOne", ExperimentAction.Show, ParameterSetName = "SwitchOneSet")]
public SwitchParameter SwitchOne { get; set; }
[Parameter("ExpTest.FeatureOne", ExperimentAction.Show, ParameterSetName = "SwitchTwoSet")]
public SwitchParameter SwitchTwo { get; set; }
protected override void EndProcessing()
{
string message = $"Hello World {Name}.";
if (ExperimentalFeature.HasEnabled("ExpTest.FeatureOne"))
{
if (SwitchOne.IsPresent) { message += "-SwitchOne is on."; }
if (SwitchTwo.IsPresent) { message += "-SwitchTwo is on."; }
}
WriteObject(message);
}
}
[Cmdlet("Invoke", "MyCommandCSharp")]
public class InvokeMyCommandCommand : PSCmdlet
{
[Parameter(Mandatory = true, ParameterSetName = "ComputerSet")]
public string UserName { get; set; }
[Parameter(Mandatory = true, ParameterSetName = "ComputerSet")]
public string ComputerName { get; set; }
[Parameter(Mandatory = true, ParameterSetName = "VMSet")]
public string VMName { get; set; }
// Enable web socket only if the feature is turned on.
[Parameter("ExpTest.FeatureOne", ExperimentAction.Show, Mandatory = true, ParameterSetName = "WebSocketSet")]
public string Token { get; set; }
[Parameter("ExpTest.FeatureOne", ExperimentAction.Show, Mandatory = true, ParameterSetName = "WebSocketSet")]
public string WebSocketUrl { get; set; }
// Add -ConfigurationName to parameter set "WebSocketSet" only if the feature is turned on.
[Parameter(ParameterSetName = "ComputerSet")]
[Parameter("ExpTest.FeatureOne", ExperimentAction.Show, ParameterSetName = "WebSocketSet")]
public string ConfigurationName { get; set; }
// Add -Port to parameter set "WebSocketSet" only if the feature is turned on.
[Parameter(ParameterSetName = "VMSet")]
[Parameter("ExpTest.FeatureOne", ExperimentAction.Show, ParameterSetName = "WebSocketSet")]
public int Port { get; set; }
[Parameter]
public int ThrottleLimit { get; set; }
[Parameter]
public string Command { get; set; }
protected override void EndProcessing()
{
switch (this.ParameterSetName)
{
case "ComputerSet": WriteObject("Invoke-MyCommand with ComputerSet"); break;
case "VMSet": WriteObject("Invoke-MyCommand with VMSet"); break;
case "WebSocketSet": WriteObject("Invoke-MyCommand with WebSocketSet"); break;
default: break;
}
}
}
[Cmdlet("Test", "MyRemotingCSharp")]
public class TestMyRemotingCommand : PSCmdlet
{
// Replace one parameter with another one when the feature is turned on.
[Parameter("ExpTest.FeatureOne", ExperimentAction.Hide)]
public string SessionName { get; set; }
[Parameter("ExpTest.FeatureOne", ExperimentAction.Show)]
public string ComputerName { get; set; }
protected override void EndProcessing() { }
}
#endregion
#region "Use 'Experimental' attribute on parameters"
[Cmdlet("Save", "MyFileCSharp")]
public class SaveMyFileCommand : PSCmdlet
{
[Parameter(ParameterSetName = "UrlSet")]
public SwitchParameter ByUrl { get; set; }
[Parameter(ParameterSetName = "RadioSet")]
public SwitchParameter ByRadio { get; set; }
[Parameter]
public string FileName { get; set; }
[Experimental("ExpTest.FeatureOne", ExperimentAction.Show)]
[Parameter]
public string Destination { get; set; }
[Experimental("ExpTest.FeatureOne", ExperimentAction.Hide)]
[Parameter(ParameterSetName = "UrlSet")]
[Parameter(ParameterSetName = "RadioSet")]
public string Configuration { get; set; }
protected override void EndProcessing() { }
}
#endregion
#region "Dynamic parameters"
public class DynamicParamOne
{
[Parameter("ExpTest.FeatureOne", ExperimentAction.Show)]
[ValidateNotNullOrEmpty]
public string ConfigFile { get; set; }
[Parameter("ExpTest.FeatureOne", ExperimentAction.Hide)]
[ValidateNotNullOrEmpty]
public string ConfigName { get; set; }
}
[Cmdlet("Test", "MyDynamicParamOneCSharp")]
public class TestMyDynamicParamOneCommand : PSCmdlet, IDynamicParameters
{
[Parameter(Position = 0)]
public string Name { get; set; }
public object GetDynamicParameters()
{
return Name == "Joe" ? new DynamicParamOne() : null;
}
protected override void EndProcessing() { }
}
public class DynamicParamTwo
{
[Experimental("ExpTest.FeatureOne", ExperimentAction.Show)]
[Parameter()]
[ValidateNotNullOrEmpty]
public string ConfigFile { get; set; }
[Experimental("ExpTest.FeatureOne", ExperimentAction.Hide)]
[Parameter()]
[ValidateNotNullOrEmpty]
public string ConfigName { get; set; }
}
[Cmdlet("Test", "MyDynamicParamTwoCSharp")]
public class TestMyDynamicParamTwoCommand : PSCmdlet, IDynamicParameters
{
[Parameter(Position = 0)]
public string Name { get; set; }
public object GetDynamicParameters()
{
return Name == "Joe" ? new DynamicParamTwo() : null;
}
protected override void EndProcessing() { }
}
#endregion
}
@@ -0,0 +1,43 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
# Module manifest for module 'ExpTest'
@{
# Version number of this module.
ModuleVersion = '0.0.1'
# Supported PSEditions
CompatiblePSEditions = @('Core')
# ID used to uniquely identify this module
GUID = '109f75d1-38c1-46b3-8995-e80661ce822d'
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = if ($EnabledExperimentalFeatures -contains "ExpTest.FeatureOne") {
'Invoke-AzureFunctionV2', 'Get-GreetingMessage', 'Invoke-MyCommand', 'Test-MyRemoting', 'Save-MyFile', 'Test-MyDynamicParamOne', 'Test-MyDynamicParamTwo'
} else {
'Invoke-AzureFunction', 'Get-GreetingMessage', 'Invoke-MyCommand', 'Test-MyRemoting', 'Save-MyFile', 'Test-MyDynamicParamOne', 'Test-MyDynamicParamTwo'
}
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = 'Invoke-AzureFunctionCSharp', 'Get-GreetingMessageCSharp', 'Invoke-MyCommandCSharp', 'Test-MyRemotingCSharp', 'Save-MyFileCSharp', 'Test-MyDynamicParamOneCSharp', 'Test-MyDynamicParamTwoCSharp'
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = @(if ($EnabledExperimentalFeatures -contains "ExpTest.FeatureOne") { 'Invoke-AzureFunction' })
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
NestedModules = @('ExpTest.psm1', 'ExpTest.dll')
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{
PSData = @{
ExperimentalFeatures = @(
@{ Name = 'ExpTest.FeatureOne'; Description = "Test feature number one." }
@{ Name = 'ExpTest.FeatureTwo'; Description = "Test feature number two." }
)
}
}
}
@@ -0,0 +1,206 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
using namespace System.Management.Automation
#region "Replace existing function"
function Invoke-AzureFunction
{
[Experimental("ExpTest.FeatureOne", [ExperimentAction]::Hide)]
param(
[string] $Token,
[string] $Command
)
"Invoke-AzureFunction Version ONE"
}
function Invoke-AzureFunctionV2
{
[Experimental("ExpTest.FeatureOne", [ExperimentAction]::Show)]
[Alias("Invoke-AzureFunction")]
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string] $Token,
[Parameter(Mandatory)]
[string] $Command
)
"Invoke-AzureFunction Version TWO"
}
#endregion
#region "Make parameter set experimental"
function Get-GreetingMessage
{
[CmdletBinding(DefaultParameterSetName = "Default")]
param(
[Parameter(Mandatory)]
[string] $Name,
## If only one parameter attribute is declared for a parameter, then the parameter is
## hidden when the parameter attribute needs to be hide.
[Parameter("ExpTest.FeatureOne", [ExperimentAction]::Show, ParameterSetName = "SwitchOneSet")]
[switch] $SwitchOne,
[Parameter("ExpTest.FeatureOne", [ExperimentAction]::Show, ParameterSetName = "SwitchTwoSet")]
[switch] $SwitchTwo
)
$message = "Hello World $Name."
if ([ExperimentalFeature]::HasEnabled("ExpTest.FeatureOne"))
{
if ($SwitchOne) { $message += "-SwitchOne is on." }
if ($SwitchTwo) { $message += "-SwitchTwo is on." }
}
Write-Output $message
}
function Invoke-MyCommand
{
param(
[Parameter(Mandatory, ParameterSetName = "ComputerSet")]
[string] $UserName,
[Parameter(Mandatory, ParameterSetName = "ComputerSet")]
[string] $ComputerName,
[Parameter(Mandatory, ParameterSetName = "VMSet")]
[string] $VMName,
## Enable web socket only if the feature is turned on.
[Parameter("ExpTest.FeatureOne", [ExperimentAction]::Show, Mandatory, ParameterSetName = "WebSocketSet")]
[string] $Token,
[Parameter("ExpTest.FeatureOne", [ExperimentAction]::Show, Mandatory, ParameterSetName = "WebSocketSet")]
[string] $WebSocketUrl,
## Add -ConfigurationName to parameter set "WebSocketSet" only if the feature is turned on.
[Parameter(ParameterSetName = "ComputerSet")]
[Parameter("ExpTest.FeatureOne", [ExperimentAction]::Show, ParameterSetName = "WebSocketSet")]
[string] $ConfigurationName,
## Add -Port to parameter set "WebSocketSet" only if the feature is turned on.
[Parameter(ParameterSetName = "VMSet")]
[Parameter("ExpTest.FeatureOne", [ExperimentAction]::Show, ParameterSetName = "WebSocketSet")]
[int] $Port,
[int] $ThrottleLimit,
[string] $Command
)
switch ($PSCmdlet.ParameterSetName)
{
"ComputerSet" { "Invoke-MyCommand with ComputerSet" }
"VMSet" { "Invoke-MyCommand with VMSet" }
"WebSocketSet" { "Invoke-MyCommand with WebSocketSet" }
}
}
function Test-MyRemoting
{
param(
## Replace one parameter with another one when the feature is turned on.
[Parameter("ExpTest.FeatureOne", [ExperimentAction]::Hide)]
[string] $SessionName,
[Parameter("ExpTest.FeatureOne", [ExperimentAction]::Show)]
[string] $ComputerName
)
}
#endregion
#region "Use 'Experimental' attribute on parameters"
function Save-MyFile
{
param(
[Parameter(ParameterSetName = "UrlSet")]
[switch] $ByUrl,
[Parameter(ParameterSetName = "RadioSet")]
[switch] $ByRadio,
[string] $FileName,
[Experimental("ExpTest.FeatureOne", [ExperimentAction]::Show)]
[string] $Destination,
[Experimental("ExpTest.FeatureOne", [ExperimentAction]::Hide)]
[Parameter(ParameterSetName = "UrlSet")]
[Parameter(ParameterSetName = "RadioSet")]
[string] $Configuration
)
}
#endregion
#region "Dynamic parameters"
function Test-MyDynamicParamOne
{
[CmdletBinding()]
param(
[string] $Name
)
## Use the parameter attribute to hide or show a dynamic parameter.
DynamicParam {
if ($Name -eq "Joe") {
$runtimeParams = [RuntimeDefinedParameterDictionary]::new()
$configFileAttributes = [System.Collections.ObjectModel.Collection[Attribute]]::new()
$configFileAttributes.Add([Parameter]::new("ExpTest.FeatureOne", [ExperimentAction]::Show))
$configFileAttributes.Add([ValidateNotNullOrEmpty]::new())
$configFileParam = [RuntimeDefinedParameter]::new("ConfigFile", [string], $configFileAttributes)
$configNameAttributes = [System.Collections.ObjectModel.Collection[Attribute]]::new()
$configNameAttributes.Add([Parameter]::new("ExpTest.FeatureOne", [ExperimentAction]::Hide))
$configNameAttributes.Add([ValidateNotNullOrEmpty]::new())
$ConfigNameParam = [RuntimeDefinedParameter]::new("ConfigName", [string], $configNameAttributes)
$runtimeParams.Add("ConfigFile", $configFileParam)
$runtimeParams.Add("ConfigName", $ConfigNameParam)
return $runtimeParams
}
}
}
function Test-MyDynamicParamTwo
{
[CmdletBinding()]
param(
[string] $Name
)
## Use the experimental attribute to hide or show a dynamic parameter.
DynamicParam {
if ($Name -eq "Joe") {
$runtimeParams = [RuntimeDefinedParameterDictionary]::new()
$configFileAttributes = [System.Collections.ObjectModel.Collection[Attribute]]::new()
$configFileAttributes.Add([Experimental]::new("ExpTest.FeatureOne", [ExperimentAction]::Show))
$configFileAttributes.Add([Parameter]::new())
$configFileAttributes.Add([ValidateNotNullOrEmpty]::new())
$configFileParam = [RuntimeDefinedParameter]::new("ConfigFile", [string], $configFileAttributes)
$configNameAttributes = [System.Collections.ObjectModel.Collection[Attribute]]::new()
$configNameAttributes.Add([Experimental]::new("ExpTest.FeatureOne", [ExperimentAction]::Hide))
$configNameAttributes.Add([Parameter]::new())
$configNameAttributes.Add([ValidateNotNullOrEmpty]::new())
$ConfigNameParam = [RuntimeDefinedParameter]::new("ConfigName", [string], $configNameAttributes)
$runtimeParams.Add("ConfigFile", $configFileParam)
$runtimeParams.Add("ConfigName", $ConfigNameParam)
return $runtimeParams
}
}
}
#endregion