pester / Pester

Pester is the ubiquitous test and mock framework for PowerShell.

Home Page:https://pester.dev/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Running Pester from a background job causes ScriptCallDepthException

oconnoda opened this issue · comments

Checklist

What is the issue?

When run in the foreground Pester produces expected results. When run from a background job, tests fail unexpectedly with a ScriptCallDepthException or InsufficientExecutionStackException. This only happens inside of a Context block. Refactoring the test code to not use Context blocks removes the problem. The call stack is about 30 inside the It block that fails. The It block and the containing Describe block are using ForEach to run 4 or 5 test cases.

Expected Behavior

The test behavior should be the same in foreground and background runs of Pester.

Steps To Reproduce

I have an elaborate test environment. Considerable effort would be required to provide sample code that reproduces the problem.

Describe your environment

The given URL is inaccessible.
PowerShell version: 5.1.17763.2931
Pester version: 5.5.0
OS: Windows 10 Enterprise 10.0.17763 Build 17763

Possible Solution?

No response

This is a known issue with PowerShell and out of our control unfortunately. The thread stack size for remote sessions including jobs is very low compared to a normal process.

See PowerShell/PowerShell#17407 where I requested to increase it for consistent behavior in PowerShell 7+. I'll try to get it reopened.

Related #1974

Thank you for your quick reply Frode. I can work around this using a runspace inside the job. However my test code uses very little stack space. Which means that almost all the available stack space is being consumed by the Pester framework. Please consider adjusting the framework design to require less stack space.

Here is a little piece of code to show how many lines are there in the stack in nested functions and in Pester. It does show that we are heavier on the stack, because we wrap all the callbacks into more code that ensures the scoping is correct and the original structure is persisted. We also have some setup code before running the functions.

function a {
    function b {
        function c {
            function d{
                [System.Environment]::StackTrace -split "\n" | Measure-Object | select -expand Count
                 try { throw } catch { Write-Host ( $_.ScriptStackTrace -split "\n" | Measure-Object | select -expand Count )} 
            }
            d
        }
        c
    }
    b
 }
 a


 invoke-pester -container (new-pestercontainer -scriptblock { Describe "a" { It "b" {  write-Host ([System.Environment]::StackTrace -split "\n" | Measure-Object | select -expand Count | out-string )
 try { throw } catch { 
    
    Write-Host ( $_.ScriptStackTrace -split "\n" | Measure-Object | select -expand Count )
} 
}} })

I see 88 .NET stack lines and 6 lines for the first example and 292 and 25 for Pester. So about 4 times that.

Counting lines in stack trace is of course not a good metric, but since powershell is interpreted, most of the lines are the "same" coming from interpreter, so I am assuming the overhead is the same, as long as we call some functions in other functions.

I don't think it is realistic for us to now start optimizing for stack consumption, because it would mean inlining some of the most complec code we have, and we don't have any good metrics to guide us.