Skip to content
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

Add an option to put WinAppDriver output in a file #151

Merged
merged 3 commits into from
Jun 25, 2024

Conversation

Steelskin
Copy link
Contributor

This enriches the internal Win32ProcessTree API to take HANDLE objects for stdin, stdout and stderr, as well as adding an option to use the parent console rather than spawning a new one.

This enriches the internal `Win32ProcessTree` API to take `HANDLE`
objects for stdin, stdout and stderr, as well as adding an option to use
the parent console rather than spawning a new one.
Copy link
Contributor

@jeffdav jeffdav left a comment

Choose a reason for hiding this comment

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

Check the INVALID_HANDLE_VALUE stuff.

Sources/WinAppDriver/Win32ProcessTree.swift Outdated Show resolved Hide resolved
Sources/WinAppDriver/Win32ProcessTree.swift Outdated Show resolved Hide resolved
Copy link
Contributor

@jeffdav jeffdav 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! :shipit:

Sources/WinAppDriver/Win32ProcessTree.swift Outdated Show resolved Hide resolved
@Steelskin Steelskin merged commit 79541bb into main Jun 25, 2024
4 checks passed
@Steelskin Steelskin deleted the fabrice/configure-redirect-output branch June 25, 2024 21:12
Copy link
Contributor

@tristanlabelle tristanlabelle left a comment

Choose a reason for hiding this comment

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

I left some posthumous comments @Steelskin !

DWORD(CREATE_SUSPENDED) | DWORD(CREATE_NEW_PROCESS_GROUP)
| (options.spawnNewConsole ? DWORD(CREATE_NEW_CONSOLE) : 0)
if let stdoutHandle = options.stdoutHandle {
startupInfo.hStdOutput = stdoutHandle
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion for more compact

startupInfo.hStdOutput = options.stdoutHandle ?? INVALID_HANDLE_VALUE
startupInfo.hStdError = options.stderrHandle ?? INVALID_HANDLE_VALUE
startupInfo.hStdInput = options.stdinHandle ?? INVALID_HANDLE_VALUE
let redirectStdHandle = options.stdoutHandle != INVALID_HANDLE_VALUE || options.stderrHandle != INVALID_HANDLE_VALUE || options.stdinHandle != INVALID_HANDLE_VALUE

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We should not set these handles to INVALID_HANDLE_VALUE because INVALID_HANDLE_VALUE (= -1 = 0xfff...) is not actually invalid but is the current process handle. So here, we use the current process input/output handles as a fallback, which makes the redirectStdHandle logic more complex than it should be.

GetStdHandle() will return NULL if the standard input/output devices have been closed, which is also a valid value to set the stdoutHandle option to if you don't want the child process to write anything, for instance. IIUC NULL HANDLE (=0) is a different value from Swift nil, since the stdoutHandle in the ProcessLaunchOptions struct is an optional.

startupInfo.hStdOutput = stdoutHandle
redirectStdHandle = true
} else {
startupInfo.hStdOutput = INVALID_HANDLE_VALUE
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this preserve the old behavior if we only set some of the handles? Should we force callers to either override all handles, or none?

@@ -66,6 +122,9 @@ public class WinAppDriver: WebDriver {
assertionFailure("WinAppDriver did not terminate within the expected time: \(error).")
}
}
if let childStdinHandle {
CloseHandle(childStdinHandle)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to keep the stdin write handle until here if just to close it? And since we have it, we could send \n for nicer termination since WinAppDriver awaits one:

C:>"C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe"
Windows Application Driver listening for requests at: http://127.0.0.1:4723/
Press ENTER to exit.

Exiting...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we close the handle, this closes stdin for the WinAppDriver process, which causes the process to shut down. That's why we need to keep it open until the process shuts down. While we could use that as a proxy to shut down WinAppDriver in a cleaner manner, we only have childStdinHandle set up if we redirect the output to a file. I'm not opposed to changing the logic but then we have no way of redirecting the output to the spawned terminal to preserve API compatibility.

}()

// Read the output file.
let output = try String(contentsOfFile: outputFile, encoding: .utf16LittleEndian)
Copy link
Contributor

Choose a reason for hiding this comment

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

Does WinAppDriver write as utf-16 when redirected to a file? That's unusual

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It writes UTF-16 either way. It's usually not noticeable because Windows Terminal handles either.

Copy link
Contributor

Choose a reason for hiding this comment

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

Terminals are supposed to decode stdout according to the GetConsoleOutputCP() of the console, so outputting UTF-16 would result in garbled contents. 🤔🤔🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably witchcraft involved:

PS > $output = & 'C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe'

PS > [system.Text.Encoding]::ASCII.GetBytes($output)
87
0
105
0
[...]

PS > $output = echo potato
PS > [system.Text.Encoding]::ASCII.GetBytes($output)
112
111
116
97
116
111

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know if that's a valid test but it is puzzling!

Sources/WinAppDriver/WinAppDriver.swift Show resolved Hide resolved
Sources/WinAppDriver/WinAppDriver.swift Show resolved Hide resolved
Sources/WinAppDriver/WinAppDriver.swift Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants