Skip to content

Run new PSReadLine test on Windows #1522

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

Merged
merged 7 commits into from
Jul 9, 2021
Merged

Run new PSReadLine test on Windows #1522

merged 7 commits into from
Jul 9, 2021

Conversation

andyleejordan
Copy link
Member

@andyleejordan andyleejordan commented Jul 6, 2021

Finishing #1514. Also replaces #1516.

@andyleejordan andyleejordan force-pushed the andschwa/tests branch 5 times, most recently from 088fdb6 to 85e60dd Compare July 7, 2021 21:51
This reverts commit 75a7175.

We are reverting this in favor of using a runtime condition set by the test
itself because this was fragile (for one, it did not work with OmniSharp running
tests).
@andyleejordan andyleejordan force-pushed the andschwa/tests branch 5 times, most recently from d41e90e to d03f3d0 Compare July 7, 2021 22:49
@andyleejordan
Copy link
Member Author

Finally stole your code @dkattan

@andyleejordan andyleejordan marked this pull request as ready for review July 7, 2021 23:33
@andyleejordan andyleejordan requested a review from rjmholt as a code owner July 7, 2021 23:33
var psReadLineType = Type.GetType("Microsoft.PowerShell.PSConsoleReadLine, Microsoft.PowerShell.PSReadLine2");

if (psReadLineType == null)
{
logger.LogWarning("PSConsoleReadline type not found: {Reason}", pwsh.HadErrors ? pwsh.Streams.Error[0].ToString() : "<Unknown reason>");
return false;
logger.LogTrace("PSConsoleReadline type not found using Type.GetType(), searching all loaded assemblies...");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rjmholt This should only happen in the case that it needs to. When Type.GetType works, then this logic is skipped. So it feels fine, though I still wish I knew why it was necessary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not saying it's "right" but I keep seeing code similar to this come up when I research the issue. I think we will get to the bottom of it as we continue to refactor but this works.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My suspicion is that this always worked in script because it always runs on the pipeline thread and through PowerShell's own type search logic. When we sift through the whole AppDomain (which is kind of a dead concept) for a type, we ignore assembly load contexts, and so that might be why the direction reflection query fails but the search succeeds. Just a theory though. An ALC shouldn't be thread-dependent though and I don't think anyone is using something like EnterContextualReflection()

{
Skip.If(IsWindows, "This test doesn't work on Windows for some reason.");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For so many reasons 😆

@andyleejordan andyleejordan force-pushed the andschwa/tests branch 2 times, most recently from 5e350a3 to 06893e7 Compare July 8, 2021 23:15
@@ -2129,75 +2144,6 @@ private static string GetStringForPSCommand(PSCommand psCommand)
return stringBuilder.ToString();
}

private void SetExecutionPolicy()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huge fan of removing this and relying on the initialSessionState. I look forward to bringing the entire InitialSessionState in instead of just the LanguageMode so we more accurately create runspaces similar to the parent.

Copy link
Contributor

@dkattan dkattan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@andyleejordan
Copy link
Member Author

@rjmholt I've been looking at Start-EditorServices and the use of -BundledModulesPath there and things seem...fishy. Let's look tomorrow if you have time, because this PR as is does not respect the user settings. So we haven't quite fixed that yet.

Comment on lines 94 to 96
var allAssemblies = AppDomain.CurrentDomain.GetAssemblies();
var assemblies = allAssemblies.FirstOrDefault(a => a.FullName.Contains("Microsoft.PowerShell.PSReadLine2"));
psReadLineType = assemblies?.ExportedTypes?.FirstOrDefault(a => a.FullName == "Microsoft.PowerShell.PSConsoleReadLine");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var allAssemblies = AppDomain.CurrentDomain.GetAssemblies();
var assemblies = allAssemblies.FirstOrDefault(a => a.FullName.Contains("Microsoft.PowerShell.PSReadLine2"));
psReadLineType = assemblies?.ExportedTypes?.FirstOrDefault(a => a.FullName == "Microsoft.PowerShell.PSConsoleReadLine");
Type psrlType = AppDomain.CurrentDomain
.GetAssemblies()
.FirstOrDefault(asm => asm.GetName().Name.Equals("Microsoft.PowerShell.PSReadLine2"))
?.ExportedTypes
?.FirstOrDefault(type => type.FullName.Equals("Microsoft.PowerShell.PSConsoleReadLine"));

var psReadLineType = Type.GetType("Microsoft.PowerShell.PSConsoleReadLine, Microsoft.PowerShell.PSReadLine2");

if (psReadLineType == null)
{
logger.LogWarning("PSConsoleReadline type not found: {Reason}", pwsh.HadErrors ? pwsh.Streams.Error[0].ToString() : "<Unknown reason>");
return false;
logger.LogTrace("PSConsoleReadline type not found using Type.GetType(), searching all loaded assemblies...");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My suspicion is that this always worked in script because it always runs on the pipeline thread and through PowerShell's own type search logic. When we sift through the whole AppDomain (which is kind of a dead concept) for a type, we ignore assembly load contexts, and so that might be why the direction reflection query fails but the search succeeds. Just a theory though. An ALC shouldn't be thread-dependent though and I don't think anyone is using something like EnterContextualReflection()

@andyleejordan andyleejordan force-pushed the andschwa/tests branch 2 times, most recently from 338c3f4 to 19a9a8f Compare July 9, 2021 20:19
This eliminates the need to have `SetExecutionPolicy` which is a slow function
that first queries a bunch of policies and then within PowerShell itself (as in,
using a cmdlet) sets it to `Bypass`. However, we just want the process scope
(AKA runspace scope) to have the execution policy set to `Bypass` all the time
so that we can import our bundled modules, such as PSReadLine.
xUnit infuriatingly defaults to using its own custom app domains (and thus
shadow copying of assemblies), which completely messes up our assembly
locations, our ability to find modules such as PSReadLine, and resolving types
from PSReadLine too.

We were not actually configuing xUnit correctly either.
dkattan and others added 2 commits July 9, 2021 14:23
This is sometimes necessary (especially in CI).

Co-authored-by: Andrew Schwartzmeyer <[email protected]>
This also simplifies our testing scenario where that path needs to be configured
at runtime, too.

Co-authored-by: Andrew Schwartzmeyer <[email protected]>
@andyleejordan andyleejordan merged commit 6f5df13 into master Jul 9, 2021
@andyleejordan andyleejordan deleted the andschwa/tests branch July 9, 2021 21:48
@andyleejordan
Copy link
Member Author

So to actually assert that we now respect BundledModulePath threw me on a bit of a loop (thanks @rjmholt for the help). E.g. with this JSON setting:

"powershell.developer.bundledModulesPath": "/Users/andschwa/Downloads/PowerShellEditorServices"

Two things have to be true: 1. the extension must be run in the VS Code debugger (such that "developer" is honored) and 2. a previous dev was "smart" and added silent fallback logic to use the extension's path if the supplied bundledModulesPath did not contain the actual modules, so it can only be tested with a perfect layout. I had originally set it to just /Users/andschwa/ expecting a failure instead of a silent ignoring of the path. It's fine, just unexpected and something I had to learn.

// behavior for consistency such that unit tests can pass in a similar environment.
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
initialSessionState.ExecutionPolicy = ExecutionPolicy.Bypass;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkattan So we resurrected the SetExecutionPolicy() function because on closer inspection, the actual issue was that in the unit test scenario we weren't having Bypass set (because the codebase's expectation is that the startup script is run with -ExecutionPolicy Bypass, like what the extension does), and the SetExecutionPolicy() actually sets the execution policy back to the original inherited scoped policy, not the process policy. That is, it override's the process/runspace's policy after everything is loaded to be equivalent to the user's machine/user policy.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rjmholt I might rename that function ResetExecutionPolicy() 😆

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That works. I'm a fan of removing large chunks of code, as long as it doesn't change expected functionality :D

@andyleejordan andyleejordan added Area-Test Issue-Enhancement A feature request (enhancement). labels Jul 13, 2021
andyleejordan added a commit that referenced this pull request Nov 30, 2021
This redoes prior work that was lost during the rewrite. Specifically
this actually respects the user configuration of `BundledModulePath`
(also used by unit tests to provide compatibililty with xUnit), and
forces the use of only our bundled PSReadLine dependency.

Essentially this redoes #1514 and #1522.
andyleejordan added a commit that referenced this pull request Nov 30, 2021
This redoes prior work that was lost during the rewrite. Specifically
this actually respects the user configuration of `BundledModulePath`
(also used by unit tests to provide compatibililty with xUnit), and
forces the use of only our bundled PSReadLine dependency.

Essentially this redoes #1514 and #1522.
@andyleejordan andyleejordan mentioned this pull request Jun 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Test Issue-Enhancement A feature request (enhancement).
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants