master
h 142 lines 4.95 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 WSLCExecutor.h
8
9 Abstract:
10
11 This file contains the declaration of the WSLCExecutor class, which
12 provides functionality to execute wslc commands and verify their results in
13 end-to-end tests.
14 --*/
15
16 #pragma once
17
18 #include "precomp.h"
19 #include "windows/Common.h"
20 #include "VTSupport.h"
21
22 namespace WSLCE2ETests {
23
24 constexpr DWORD DefaultWaitTimeoutMs = 60000; // 60 seconds
25
26 enum class ElevationType
27 {
28 Elevated,
29 NonElevated
30 };
31
32 inline std::wstring GetWslcPath()
33 {
34 return (std::filesystem::path(wsl::windows::common::wslutil::GetMsiPackagePath().value()) / L"wslc.exe").wstring();
35 }
36
37 struct WSLCExecutionResult
38 {
39 std::wstring CommandLine{};
40 std::optional<std::wstring> Stdout{};
41 std::optional<std::wstring> Stderr{};
42 std::optional<DWORD> ExitCode{};
43 void Dump(bool escapeStrings = false) const;
44 void Verify(const WSLCExecutionResult& expected) const;
45 std::vector<std::wstring> GetStdoutLines() const;
46 std::wstring GetStdoutOneLine() const;
47 bool StdoutContainsLine(const std::wstring& expectedLine) const;
48 bool StdoutContainsSubstring(const std::wstring& substring) const;
49 bool StderrContainsSubstring(const std::wstring& substring) const;
50 };
51
52 struct PseudoConsole
53 {
54 NON_COPYABLE(PseudoConsole);
55 DEFAULT_MOVABLE(PseudoConsole);
56
57 PseudoConsole(SHORT columns, SHORT rows);
58
59 wil::unique_hfile InputWrite;
60 wil::unique_hfile OutputRead;
61 wsl::windows::common::helpers::unique_pseudo_console Handle;
62 };
63
64 // Interactive session for testing wslc commands that require stdin/stdout interaction.
65 // Uses PartialHandleRead for race-free output validation
66 struct WSLCInteractiveSession
67 {
68 WSLCInteractiveSession(
69 std::wstring commandLine,
70 wil::unique_hfile stdinWrite,
71 wil::unique_hfile stdoutRead,
72 wil::unique_hfile stderrRead,
73 wil::unique_handle processHandle,
74 wil::unique_handle nonElevatedToken = wil::unique_handle{},
75 wsl::windows::common::helpers::unique_pseudo_console pseudoConsole = {});
76 ~WSLCInteractiveSession();
77
78 // Non-copyable, non-movable
79 WSLCInteractiveSession(const WSLCInteractiveSession&) = delete;
80 WSLCInteractiveSession& operator=(const WSLCInteractiveSession&) = delete;
81 WSLCInteractiveSession(WSLCInteractiveSession&&) = delete;
82 WSLCInteractiveSession& operator=(WSLCInteractiveSession&&) = delete;
83
84 std::wstring CommandLine;
85
86 void Write(const std::string& data);
87 void WriteLine(const std::string& line);
88 void ExpectStdout(const std::string& expected);
89 void ExpectStderr(const std::string& expected);
90 void ExpectCommandEcho(const std::string& command);
91
92 // Convenience overloads for VT sequence helpers.
93 void ExpectStdout(const wsl::windows::common::vt::Sequence& expected)
94 {
95 ExpectStdout(wsl::windows::common::string::WideToMultiByte(expected.Get()));
96 }
97 void ExpectStderr(const wsl::windows::common::vt::Sequence& expected)
98 {
99 ExpectStderr(wsl::windows::common::string::WideToMultiByte(expected.Get()));
100 }
101
102 void IgnoreSequence(const std::string& sequence);
103
104 std::string GetStdoutData() const;
105
106 void ResizePseudoConsole(SHORT columns, SHORT rows);
107
108 bool IsRunning() const;
109 void CloseStdin();
110 std::optional<int> GetExitCode() const;
111 void WaitForExit(DWORD timeoutMs = DefaultWaitTimeoutMs);
112 int Wait(DWORD timeoutMs = DefaultWaitTimeoutMs);
113 bool Terminate(UINT exitCode = 1);
114 void VerifyNoErrors();
115 int Exit(DWORD timeoutMs = DefaultWaitTimeoutMs);
116 int ExitAndVerifyNoErrors(DWORD timeoutMs = DefaultWaitTimeoutMs);
117
118 private:
119 wil::unique_hfile m_stdinWrite;
120 wil::unique_hfile m_stdoutRead;
121 wil::unique_hfile m_stderrRead;
122 wsl::windows::common::helpers::unique_pseudo_console m_pseudoConsole;
123 wil::unique_handle m_processHandle;
124 wil::unique_handle m_nonElevatedToken; // Keep token alive for the lifetime of the session
125 std::unique_ptr<PartialHandleRead> m_stdoutReader;
126 std::unique_ptr<PartialHandleRead> m_stderrReader;
127 std::optional<std::string> m_ignoreSequence;
128 };
129
130 WSLCExecutionResult RunWslc(const std::wstring& commandLine, ElevationType elevationType = ElevationType::Elevated, HANDLE stdinHandle = nullptr);
131 WSLCExecutionResult RunWslcAndRedirectToFile(
132 const std::wstring& commandLine,
133 std::optional<std::filesystem::path> outputPath = std::nullopt,
134 ElevationType elevationType = ElevationType::Elevated);
135 WSLCExecutionResult RunWslcWithStdinFile(
136 const std::wstring& commandLine, const std::filesystem::path& stdinFilePath, ElevationType elevationType = ElevationType::Elevated);
137 void RunWslcAndVerify(const std::wstring& cmd, const WSLCExecutionResult& expected, ElevationType elevationType = ElevationType::Elevated);
138
139 WSLCInteractiveSession RunWslcInteractive(
140 const std::wstring& commandLine, ElevationType elevationType = ElevationType::Elevated, std::optional<PseudoConsole> pseudoConsole = std::nullopt);
141
142 } // namespace WSLCE2ETests