-
Notifications
You must be signed in to change notification settings - Fork 234
Re-enable DebugServiceTests
suite
#1635
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
8179caa
to
730ca08
Compare
Pushed a commit to the wrong branch, just reverted it, not a good look for my first day on the job :P |
d7f5beb
to
8d1e246
Compare
@JustinGrote Progress! The first |
@andschwa great! Once this gets merged I'll rebase my existing PRs and try to add tests accordingly. |
c312ed2
to
2f023a7
Compare
@JustinGrote Hm, everything but the four that I've skipped (and they're unfortunately indicative of real broken things) pass on my Mac...but not in Windows CI 😢 |
The common failure is around the event not getting added to the debugger stopped queue, which is what breaks the first skipped test and I've been debugging. I believe there's a race condition in the debugger or its handlers. Working on finding it. @SeeminglyScience if you have any ideas, let me know! |
2d0658a
to
93548af
Compare
@SeeminglyScience @JustinGrote I found the deadlock! In the tests, any code that calls into Unfortunately there's still a large hill (but not a mountain any more) of work here: I need to clean all of this up for one, and for two, the set variable logic is broken and the associated tests currently skipped. I might punt the latter. |
f009d2e
to
d7b57a5
Compare
DebugServiceTests
suiteDebugServiceTests
suite
@andschwa look at you with your green checkmarks :). Thanks for what I'm sure was a very perplexing effort. |
src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ConfigurationDoneHandler.cs
Show resolved
Hide resolved
src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs
Show resolved
Hide resolved
src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs
Show resolved
Hide resolved
DebugServiceTests
suiteDebugServiceTests
suite
if (previousRunspaceFrame.Runspace != CurrentPowerShell.Runspace) | ||
// Because the frame has been popped, we cannot rely on 'CurrentPowerShell.Runspace' | ||
// as it may be empty. | ||
if (previousRunspaceFrame.Runspace != frame.PowerShell.Runspace) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rjmholt, Dongbo and I weren't sure what this logic should be. Right now, we're changing it slightly to compare the previous runspace against the previous PowerShell frame's runspace, which seemingly fixes what we think was an oversight. I've stashed a change that reverts the logic to compare to the new PowerShell frame's runspace, except with a check if there are no more PowerShell frames. We'll see what happens!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like it's trying to check if popping the current frame puts us into a different runspace than before.
e.g.
- Process start, default frame
- Enter-PSSession, new remote frame
- Exit-PSSession, pop frame back to 1
- Check CurrentPowerShell, see if we've moved to a different runspace.
test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. @andschwa walked me through the changes, thanks Andy!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work! A couple of mostly small things
if (previousRunspaceFrame.Runspace != CurrentPowerShell.Runspace) | ||
// Because the frame has been popped, we cannot rely on 'CurrentPowerShell.Runspace' | ||
// as it may be empty. | ||
if (previousRunspaceFrame.Runspace != frame.PowerShell.Runspace) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like it's trying to check if popping the current frame puts us into a different runspace than before.
e.g.
- Process start, default frame
- Enter-PSSession, new remote frame
- Exit-PSSession, pop frame back to 1
- Check CurrentPowerShell, see if we've moved to a different runspace.
src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs
Show resolved
Hide resolved
test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs
Outdated
Show resolved
Hide resolved
@SeeminglyScience For some reason I can't reply to this: I get that's what it's trying to do, but I'm having trouble following the logic. The existing logic runs into a null dereference issue, because first a frame is popped, and then we do a peek on the frame stack. If this logic is correct it needs to be adjusted for the case where the stack is empty after that pop. The current change in this PR assumes that the existing logic was an oversight and that it was intending to compare to the frame being popped. What do you think? Dongbo and I had decided just to test one, see what happens, and change it if needed 😅 |
d7b57a5
to
04f8f67
Compare
@daxian-dbw Upon examination, yes your suspicion is correct: xUnit adds its own synchronization context even if parallelism is disabled, since we're using |
Is it possible that Unless I'm missing something, right now it's checking if the current frame is on the current runspace, but that'll always be the case. I think the current fix is maybe hiding a different bug. |
I don't think so. The case where it's an empty stack is an easy one: when the last PowerShell frame is being popped, the stack is now empty.
This I agree with, it doesn't seem right to me now. Potential fix: if (_psFrameStack.Count != 0 && previousRunspaceFrame.Runspace != _psFrameStack.Peek().PowerShell.Runspace) |
Something still seems a little off. I think there should always be something on the stack unless I'm remembering wrong. Is it possible this only happens at tear down? And just a lot more noticeable in tests since it's happening more often? If that's the case then yeah that seems like a good fix. If it's not only during tear down then I'm a little confused how it can function after Edit: oh that might be what you're saying in the first part there? |
@SeeminglyScience I stepped through it a few more times and I'm convinced the null-dereference is happening during cleanup, and so was an overlooked edge case. Here's what I'm about to rebase into this PR: private void PopPowerShell(RunspaceChangeAction runspaceChangeAction = RunspaceChangeAction.Exit)
{
_shouldExit = false;
PowerShellContextFrame frame = _psFrameStack.Pop();
try
{
// If we're changing runspace, make sure we move the handlers over. If we just
// popped the last frame, then we're exiting and should pop the runspace too.
if (_psFrameStack.Count == 0
|| _runspaceStack.Peek().Runspace != _psFrameStack.Peek().PowerShell.Runspace)
{
RunspaceFrame previousRunspaceFrame = _runspaceStack.Pop();
RemoveRunspaceEventHandlers(previousRunspaceFrame.Runspace);
// If there is still a runspace on the stack, then we need to re-register the
// handlers. Otherwise we're exiting and so don't need to run 'RunspaceChanged'.
if (_runspaceStack.Count > 0)
{
RunspaceFrame newRunspaceFrame = _runspaceStack.Peek();
AddRunspaceEventHandlers(newRunspaceFrame.Runspace);
RunspaceChanged?.Invoke(
this,
new RunspaceChangedEventArgs(
runspaceChangeAction,
previousRunspaceFrame.RunspaceInfo,
newRunspaceFrame.RunspaceInfo));
}
}
}
finally
{
frame.Dispose();
}
} |
This was a Roslyn analyzer automatic change to fix the nested if statements.
* Renamed `remoteFileManager` to `_remoteFileManager` for consistency * Made `globalScopeVariables` internal for unit testing * Deleted dead constructor * Removed unnecessary `this.` prefixes * Applied Roslyn analyzer suggested uses of conditional access * Used `catch () when ()` syntax instead of re-throwing * Use const constants
* Removed uncessary using directives and sorted * Applied `readonly` and `const` suggestions * Updated use of `psesHost` instead of `powerShellContextService` * Call `GC.SuppressFinalize()` in `Dispose()` to avoid warning * Improved names of things * Removed unnecessary `this.` prefixes * Added easy-to-use PowerShell execution wrappers * Removed all logic around `sessionStateQueue` because of new pipeline * Fixed threading assumptions by using `ConfigureAwait(true)` * Used `Task.Run()` to avoid deadlock when calling onto pipeline thread * Replaced `FirstOrDefault` with `Array.Find` * Removed deprecated data from `DebuggerAcceptsScriptArgs` * Stopped aborting at end of each test because xUnit disposes everything * Ditto for waiting on `executeTask` * Skip broken tests around setting variables (punting this fix) * General reorginzation and cleanup
While this wasn't necessary to get the debug service unit tests running again, it seems like an unncessary code path that causes unit tests to behave slightly differently than production code, which I don't like.
04f8f67
to
f14163d
Compare
Please see commits for work done.