Files
PowerShell-PowerShell/test/powershell/Modules/Microsoft.PowerShell.Diagnostics/CounterTestHelperFunctions.ps1
T
James Truher [MSFT] c97ca777df Jameswtruher/travisdailybuild (#2958)
* Stifle progress output in build.psm1 for some operations

Modify test failure presentation to use platform available XML methods

* Add timeout support for returning runtime parsing errors

Some of the language/parser tests have been hanging in a non-reproducable manner which
causes the CI system to invalidate the entire run. This change adds support for timeout
which will fail a test if it runs to long, rather than invalidate the entire run.

current behavior is still supported, and is not done in a new session:
PS> get-runtimeerror -src '1/'
At line:1 char:3
+ 1/
+   ~
You must provide a value expression following the '/' operator.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ExpectedValueExpression

Adding a timeout will do the operation in a async powershell session
PS> get-runtimeerror -src '1/' -timeout 5
You must provide a value expression following the '/' operator.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ExpectedValueExpression

If the operation takes longer than the supplied timeout, a timeout error will be returned
PS> get-runtimeerror -src 'start-sleep 6' -timeout 2
get-runtimeerror : Operation Timed Out ('start-sleep 6')
At line:1 char:1
+ get-runtimeerror -src 'start-sleep 6' -timeout 2
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-RuntimeError

* Modify native linux command tests to skip on Windows and pending on Mac

* remove verbose and progress output from help tests

* Be sure that Feature Counter tests only run on Windows

Also, only call add-type in CounterTestHelperFunctions.ps1 if we're going to actually run the tests

* do not run any get-computerinfo tests on non-windows systems

* suppress progress output from PowerShell Get tests

* remove -quiet from API and CRON Builds

Travis watches output from the build to ensure that it hasn't hung
we need to find a balance between too much output and not enough output.
A run which has too much output is killed because it looks like an error loop
A run which has too little output is killed because it looks like a hang

* Remove commented line in Import-Counter.Tests.ps1

Remove extraneous extra line in PowerShellGet.Tests.ps1

* Change `-as "type"` to `-as [type]` in build.psm1

Alter timeout to 10 seconds to be improve chances of not timing out for runtime parser checks
improve logic for counter tests to also skip for IoT

* use the existing function of SkipCounterTests rather than duplicate the logic in import-counter.tests.ps1
2017-01-10 14:42:27 -08:00

299 lines
9.4 KiB
PowerShell

<############################################################################################
# File: CounterTestHelperFunctions.ps1
# Provides functions common to the performance counter Pester tests.
############################################################################################>
# Create a helper class providing facilities for translation of
# counter names and counter paths
$helperSource = @"
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
public class TestCounterHelper
{
private const long PDH_MORE_DATA = 0x800007D2L;
private const int PDH_MAX_COUNTER_NAME = 1024;
private const int PDH_MAX_COUNTER_PATH = 2048;
private const string SubKeyPath = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009";
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct PDH_COUNTER_PATH_ELEMENTS
{
[MarshalAs(UnmanagedType.LPWStr)]
public string MachineName;
[MarshalAs(UnmanagedType.LPWStr)]
public string ObjectName;
[MarshalAs(UnmanagedType.LPWStr)]
public string InstanceName;
[MarshalAs(UnmanagedType.LPWStr)]
public string ParentInstance;
public UInt32 InstanceIndex;
[MarshalAs(UnmanagedType.LPWStr)]
public string CounterName;
}
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
private static extern uint PdhMakeCounterPath(ref PDH_COUNTER_PATH_ELEMENTS pCounterPathElements,
StringBuilder szFullPathBuffer,
ref uint pcchBufferSize,
UInt32 dwFlags);
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
private static extern uint PdhParseCounterPath(string szFullPathBuffer,
IntPtr pCounterPathElements, //PDH_COUNTER_PATH_ELEMENTS
ref IntPtr pdwBufferSize,
uint dwFlags);
[DllImport("pdh.dll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern UInt32 PdhLookupPerfNameByIndex(string szMachineName,
uint dwNameIndex,
System.Text.StringBuilder szNameBuffer,
ref uint pcchNameBufferSize);
private string[] _counters;
public TestCounterHelper(string[] counters)
{
_counters = counters;
}
public string TranslateCounterName(string name)
{
var loweredName = name.ToLowerInvariant();
for (var i = 1; i < _counters.Length - 1; i += 2)
{
if (_counters[i].ToLowerInvariant() == loweredName)
{
try
{
var index = Convert.ToUInt32(_counters[i - 1], CultureInfo.InvariantCulture);
var sb = new StringBuilder(PDH_MAX_COUNTER_NAME);
var bufSize = (uint)sb.Capacity;
var result = PdhLookupPerfNameByIndex(null, index, sb, ref bufSize);
if (result == 0)
return sb.ToString().Substring(0, (int)bufSize - 1);
}
catch
{
// do nothing, we just won't translate
}
break;
}
}
// return original path if translation failed
return name;
}
public string TranslateCounterPath(string path)
{
var bufSize = new IntPtr(0);
var result = PdhParseCounterPath(path,
IntPtr.Zero,
ref bufSize,
0);
if (result != 0 && result != PDH_MORE_DATA)
return path;
IntPtr structPointer = Marshal.AllocHGlobal(bufSize.ToInt32());
try
{
result = PdhParseCounterPath(path,
structPointer,
ref bufSize,
0);
if (result == 0)
{
var cpe = Marshal.PtrToStructure<PDH_COUNTER_PATH_ELEMENTS>(structPointer);
cpe.ObjectName = TranslateCounterName(cpe.ObjectName);
cpe.CounterName = TranslateCounterName(cpe.CounterName);
var sb = new StringBuilder(PDH_MAX_COUNTER_NAME);
var pathSize = (uint)sb.Capacity;
result = PdhMakeCounterPath(ref cpe, sb, ref pathSize, 0);
if (result == 0)
return sb.ToString().Substring(0, (int)pathSize - 1);
}
}
finally
{
Marshal.FreeHGlobal(structPointer);
}
// return original path if translation failed
return path;
}
}
"@
if ( $IsWindows )
{
Add-Type -TypeDefinition $helperSource
}
# Strip off machine name, if present, from counter path
function RemoveMachineName
{
param (
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]
$path
)
if ($path.StartsWith("\\"))
{
return $path.SubString($path.IndexOf("\", 2))
}
else
{
return $path
}
}
# Retrieve the counters array from the Registry
function GetCounters
{
if ( $IsWindows )
{
$key = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage'
return (Get-ItemProperty -Path $key -Name Counter).Counter
}
}
# Translate a counter name from English to a localized counter name
function TranslateCounterName
{
param (
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]
$counterName
)
$counters = GetCounters
if ($counters -and ($counters.Length -gt 1))
{
$counterHelper = New-Object -TypeName "TestCounterHelper" -ArgumentList (, $counters)
return $counterHelper.TranslateCounterName($counterName)
}
return $counterName
}
# Translate a counter path from English to a localized counter path
function TranslateCounterPath
{
param (
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]
$path
)
$counters = GetCounters
if ($counters -and ($counters.Length -gt 1))
{
$counterHelper = New-Object -TypeName "TestCounterHelper" -ArgumentList (, $counters)
$rv = $counterHelper.TranslateCounterPath($path)
# if our original path had no machine name,
# we don't want one on our translated path
if (-not $path.StartsWith("\\"))
{
$rv = RemoveMachineName $rv
}
return $rv
}
return $path
}
# Compare two DateTime objects for relative equality.
#
# Exporting lops fractional milliseconds off the time stamp,
# so simply comparing the DateTime values isn't sufficient
function DateTimesAreEqualish
{
param (
[Parameter(Mandatory=$true)]
[ValidateNotNull()]
[DateTime]
$dtA,
[Parameter(Mandatory)]
[ValidateNotNull()]
[DateTime]
$dtB
)
$span = $dtA - $dtB
return ([math]::Floor([math]::Abs($span.TotalMilliseconds)) -eq 0)
}
# Compare the content of counter sets
function CompareCounterSets
{
param (
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
$setA,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
$setB
)
$setA.Length | Should Be $setB.Length
# Depending on the kinds of counters used, the first record in
# exported counters are likely to have embty items, so we'll
# start comparing at the second item.
#
# Note that this is not a bug in either the cmdlets or the tests
# script, but rather is the behavior of the underlying Windows
# PDH functions that perform the actual exporting of counter data.
for ($i = 1; $i -lt $setA.Length; $i++)
{
$setA[$i].CounterSamples.Length | Should Be $setB[$i].CounterSamples.Length
$samplesA = ($setA[$i].CounterSamples | sort -Property Path)
$samplesB = ($setB[$i].CounterSamples | sort -Property Path)
(DateTimesAreEqualish $setA[$i].TimeStamp $setB[$i].TimeStamp) | Should Be $true
for ($j = 0; $j -lt $samplesA.Length; $j++)
{
$sampleA = $samplesA[$j]
$sampleB = $samplesB[$j]
(DateTimesAreEqualish $sampleA.TimeStamp $sampleB.TimeStamp) | Should Be $true
$sampleA.Path | Should Be $sampleB.Path
$sampleA.CookedValue | Should Be $sampleB.CookedValue
}
}
}
function SkipCounterTests
{
if ([System.Management.Automation.Platform]::IsLinux -or
[System.Management.Automation.Platform]::IsOSX -or
[System.Management.Automation.Platform]::IsIoT)
{
return $true
}
return $false
}