MegaBites-AI/Windows-powershell
0372
1# Copyright (c) Microsoft Corporation.2# Licensed under the MIT License.3 4# This came from monad/tests/ci/PowerShell/tests/Commands/Cmdlets/pester.utility.command.tests.ps15Describe "Trace-Command" -tags "CI" {6 7 Context "Listener options" {8 BeforeAll {9 $logFile = New-Item "TestDrive:/traceCommandLog.txt" -Force10 $actualLogFile = New-Item "TestDrive:/actualTraceCommandLog.txt" -Force11 }12 13 AfterEach {14 Remove-Item "TestDrive:/traceCommandLog.txt" -Force -ErrorAction SilentlyContinue15 Remove-Item "TestDrive:/actualTraceCommandLog.txt" -Force -ErrorAction SilentlyContinue16 }17 18 # LogicalOperationStack is not in .NET Core19 It "LogicalOperationStack works" -Skip:$IsCoreCLR {20 $keyword = "Trace_Command_ListenerOption_LogicalOperationStack_Foo"21 $stack = [System.Diagnostics.Trace]::CorrelationManager.LogicalOperationStack22 $stack.Push($keyword)23 24 Trace-Command -Name * -Expression {Write-Output Foo} -ListenerOption LogicalOperationStack -FilePath $logfile25 26 $log = Get-Content $logfile | Where-Object {$_ -like "*LogicalOperationStack=$keyword*"}27 $log.Count | Should -BeGreaterThan 028 }29 30 # GetStackTrace is not in .NET Core31 It "Callstack works" -Skip:$IsCoreCLR {32 Trace-Command -Name * -Expression {Write-Output Foo} -ListenerOption Callstack -FilePath $logfile33 $log = Get-Content $logfile | Where-Object {$_ -like "*Callstack= * System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)*"}34 $log.Count | Should -BeGreaterThan 035 }36 37 It "Datetime works" {38 $expectedDate = Trace-Command -Name * -Expression {Get-Date} -ListenerOption DateTime -FilePath $logfile39 $log = Get-Content $logfile | Where-Object {$_ -like "*DateTime=*"}40 $results = $log | ForEach-Object {[DateTime]::Parse($_.Split("=")[1])}41 42 ## allow a gap of 6 seconds. All traces should be finished within 6 seconds.43 $allowedGap = [timespan](60 * 1000 * 1000)44 $results | ForEach-Object {45 $actualGap = $_ - $expectedDate;46 if ($expectedDate -gt $_)47 {48 $actualGap = $expectedDate - $_;49 }50 51 $allowedGap | Should -BeGreaterThan $actualGap52 }53 }54 55 It "None options has no effect" {56 Trace-Command -Name * -Expression {Write-Output Foo} -ListenerOption None -FilePath $actualLogfile57 Trace-Command -Name * -Expression {Write-Output Foo} -FilePath $logfile58 59 Compare-Object (Get-Content $actualLogfile) (Get-Content $logfile) | Should -BeNullOrEmpty60 }61 62 It "ThreadID works" {63 Trace-Command -Name * -Expression {Write-Output Foo} -ListenerOption ThreadId -FilePath $logfile64 $log = Get-Content $logfile | Where-Object {$_ -like "*ThreadID=*"}65 $results = $log | ForEach-Object {$_.Split("=")[1]}66 67 $results | ForEach-Object { $_ | Should -Be ([threading.thread]::CurrentThread.ManagedThreadId) }68 }69 70 It "Timestamp creates logs in ascending order" {71 Trace-Command -Name * -Expression {Write-Output Foo} -ListenerOption Timestamp -FilePath $logfile72 $log = Get-Content $logfile | Where-Object {$_ -like "*Timestamp=*"}73 $results = $log | ForEach-Object {$_.Split("=")[1]}74 $sortedResults = $results | Sort-Object75 $sortedResults | Should -Be $results76 }77 78 It "ProcessId logs current process Id" {79 Trace-Command -Name * -Expression {Write-Output Foo} -ListenerOption ProcessId -FilePath $logfile80 $log = Get-Content $logfile | Where-Object {$_ -like "*ProcessID=*"}81 $results = $log | ForEach-Object {$_.Split("=")[1]}82 83 $results | ForEach-Object { $_ | Should -Be $PID }84 }85 }86 87 Context "MethodInvocation traces" {88 89 BeforeAll {90 $filePath = Join-Path $TestDrive 'testtracefile.txt'91 92 class MyClass {93 MyClass() {}94 MyClass([int]$arg) {}95 96 [void]Method() { return }97 [void]Method([string]$arg) { return }98 [void]Method([int]$arg) { return }99 100 [string]ReturnMethod() { return "foo" }101 102 static [void]StaticMethod() { return }103 static [void]StaticMethod([string]$arg) { return }104 }105 106 # C# classes support more features than pwsh classes107 Add-Type -TypeDefinition @'108namespace TraceCommandTests;109 110public sealed class OverloadTests111{112 public int PropertySetter { get; set; }113 114 public OverloadTests() {}115 public OverloadTests(int value)116 {117 PropertySetter = value;118 }119 120 public void GenericMethod<T>()121 {}122 123 public T GenericMethodWithArg<T>(T obj) => obj;124 125 public void MethodWithDefault(string arg1, int optional = 1)126 {}127 128 public void MethodWithOut(out int val)129 {130 val = 1;131 }132 133 public void MethodWithRef(ref int val)134 {135 val = 1;136 }137}138'@139 }140 141 AfterEach {142 Remove-Item $filePath -Force -ErrorAction SilentlyContinue143 }144 145 It "Traces instance method" {146 $myClass = [MyClass]::new()147 Trace-Command -Name MethodInvocation -Expression {148 $myClass.Method(1)149 } -FilePath $filePath150 Get-Content $filePath | Should -BeLike "*Invoking method: void Method(int arg)"151 }152 153 It "Traces static method" {154 Trace-Command -Name MethodInvocation -Expression {155 [MyClass]::StaticMethod(1)156 } -FilePath $filePath157 Get-Content $filePath | Should -BeLike "*Invoking method: static void StaticMethod(string arg)"158 }159 160 It "Traces method with return type" {161 $myClass = [MyClass]::new()162 Trace-Command -Name MethodInvocation -Expression {163 $myClass.ReturnMethod()164 } -FilePath $filePath165 Get-Content $filePath | Should -BeLike "*Invoking method: string ReturnMethod()"166 }167 168 It "Traces constructor" {169 Trace-Command -Name MethodInvocation -Expression {170 [TraceCommandTests.OverloadTests]::new("1234")171 } -FilePath $filePath172 Get-Content $filePath | Should -BeLike "*Invoking method: TraceCommandTests.OverloadTests new(int value)"173 }174 175 It "Traces Property setter invoked as a method" {176 $obj = [TraceCommandTests.OverloadTests]::new()177 Trace-Command -Name MethodInvocation -Expression {178 $obj.set_PropertySetter(1234)179 } -FilePath $filePath180 Get-Content $filePath | Should -BeLike "*Invoking method: void set_PropertySetter(int value)"181 }182 183 It "Traces generic method" {184 $obj = [TraceCommandTests.OverloadTests]::new()185 Trace-Command -Name MethodInvocation -Expression {186 $obj.GenericMethod[int]()187 } -FilePath $filePath188 Get-Content $filePath | Should -BeLike "*Invoking method: void GenericMethod``[int``]()"189 }190 191 It "Traces generic method with argument" {192 $obj = [TraceCommandTests.OverloadTests]::new()193 Trace-Command -Name MethodInvocation -Expression {194 $obj.GenericMethodWithArg("foo")195 } -FilePath $filePath196 Get-Content $filePath | Should -BeLike "*Invoking method: string GenericMethodWithArg``[string``](string obj)"197 }198 199 It "Traces .NET call with default value" {200 $obj = [TraceCommandTests.OverloadTests]::new()201 Trace-Command -Name MethodInvocation -Expression {202 $obj.MethodWithDefault("foo")203 } -FilePath $filePath204 Get-Content $filePath | Should -BeLike "*Invoking method: void MethodWithDefault(string arg1, int optional = 1)"205 }206 207 It "Traces method with ref argument" {208 $obj = [TraceCommandTests.OverloadTests]::new()209 $v = 1210 211 Trace-Command -Name MethodInvocation -Expression {212 $obj.MethodWithRef([ref]$v)213 } -FilePath $filePath214 # [ref] goes through the binder so will trigger the first trace215 Get-Content $filePath | Select-Object -Skip 1 | Should -BeLike "*Invoking method: void MethodWithRef(``[ref``] int val)"216 }217 218 It "Traces method with out argument" {219 $obj = [TraceCommandTests.OverloadTests]::new()220 $v = 1221 222 Trace-Command -Name MethodInvocation -Expression {223 $obj.MethodWithOut([ref]$v)224 } -FilePath $filePath225 # [ref] goes through the binder so will trigger the first trace226 Get-Content $filePath | Select-Object -Skip 1 | Should -BeLike "*Invoking method: void MethodWithOut(``[ref``] int val)"227 }228 229 It "Traces a binding error" {230 Trace-Command -Name MethodInvocation -Expression {231 # try/catch is used as error formatter will hit the trace as well232 try {233 [System.Runtime.InteropServices.Marshal]::SizeOf([int])234 }235 catch {236 # Satisfy codefactor237 $_ | Out-Null238 }239 } -FilePath $filePath240 # type fqn is used, the wildcard avoids hardcoding that241 Get-Content $filePath | Should -BeLike "*Invoking method: static int SizeOf``[System.RuntimeType, *``](System.RuntimeType, * structure)"242 }243 244 It "Traces LINQ call" {245 Trace-Command -Name MethodInvocation -Expression {246 [System.Linq.Enumerable]::Union([int[]]@(1, 2), [int[]]@(3, 4))247 } -FilePath $filePath248 Get-Content $filePath | Should -BeLike "*Invoking method: static System.Collections.Generic.IEnumerable``[int``] Union``[int``](System.Collections.Generic.IEnumerable``[int``] first, System.Collections.Generic.IEnumerable``[int``] second)"249 }250 }251 252 Context "Trace-Command tests for code coverage" {253 254 BeforeAll {255 $filePath = Join-Path $TestDrive 'testtracefile.txt'256 }257 258 AfterEach {259 Remove-Item $filePath -Force -ErrorAction SilentlyContinue260 }261 262 It "Get non-existing trace source" {263 { '34E7F9FA-EBFB-4D21-A7D2-D7D102E2CC2F' | Get-TraceSource -ErrorAction Stop} | Should -Throw -ErrorId 'TraceSourceNotFound,Microsoft.PowerShell.Commands.GetTraceSourceCommand'264 }265 266 It "Set-TraceSource to file and RemoveFileListener wildcard" {267 $null = Set-TraceSource -Name "ParameterBinding" -Option ExecutionFlow -FilePath $filePath -Force -ListenerOption "ProcessId,TimeStamp" -PassThru268 Set-TraceSource -Name "ParameterBinding" -RemoveFileListener *269 Get-Content $filePath -Raw | Should -Match 'ParameterBinding Information'270 }271 272 It "Trace-Command -Command with error" {273 { Trace-Command -Name ParameterBinding -Command 'Get-PSDrive' -ArgumentList 'NonExistingDrive' -Option ExecutionFlow -FilePath $filePath -Force -ListenerOption "ProcessId,TimeStamp" -ErrorAction Stop } |274 Should -Throw -ErrorId 'GetLocationNoMatchingDrive,Microsoft.PowerShell.Commands.TraceCommandCommand'275 }276 277 It "Trace-Command fails for non-filesystem paths" {278 { Trace-Command -Name ParameterBinding -Expression {$null} -FilePath "Env:\Test" -ErrorAction Stop } | Should -Throw -ErrorId 'FileListenerPathResolutionFailed,Microsoft.PowerShell.Commands.TraceCommandCommand'279 }280 281 It "Trace-Command to readonly file" {282 $null = New-Item $filePath -Force283 Set-ItemProperty $filePath -Name IsReadOnly -Value $true284 Trace-Command -Name ParameterBinding -Command 'Get-PSDrive' -FilePath $filePath -Force285 Get-Content $filePath -Raw | Should -Match 'ParameterBinding Information'286 }287 288 It "Trace-Command using Path parameter alias" {289 $null = New-Item $filePath -Force290 Trace-Command -Name ParameterBinding -Command 'Get-PSDrive' -Path $filePath -Force291 Get-Content $filePath -Raw | Should -Match 'ParameterBinding Information'292 }293 294 It "Trace-Command contains wildcard characters" {295 $a = Trace-Command -Name ParameterB* -Command 'get-alias'296 $a.count | Should -BeGreaterThan 0297 }298 }299}300 