microsoft/TypeAgent

Public

mirrored fromhttps://github.com/microsoft/TypeAgentAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
dev/georgeng/autogen-cicd

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

dotnet/autoShell.Tests/EndToEndTests.cs

273lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4using System.Text.Json;
5
6namespace autoShell.Tests;
7
8/// <summary>
9/// End-to-end tests that launch autoShell.exe as a child process and communicate
10/// via the stdin/stdout JSON protocol. Tests the full pipeline including process
11/// startup, JSON parsing, command dispatch, and response serialization.
12/// </summary>
13[Trait("Category", "E2E")]
14public sealed class EndToEndTests : IDisposable
15{
16 private readonly AutoShellProcess _process;
17
18 public EndToEndTests()
19 {
20 _process = AutoShellProcess.StartInteractive();
21 }
22
23 public void Dispose()
24 {
25 _process.Dispose();
26 }
27
28 // --- Query commands (assert JSON stdout) ---
29
30 /// <summary>
31 /// Verifies that ListAppNames returns a valid JSON array of app names via stdout.
32 /// </summary>
33 [Fact]
34 public async Task ListAppNames_ReturnsJsonArray()
35 {
36 _process.SendCommand("""{"actionName":"ListAppNames","parameters":{}}""");
37
38 string? response = await _process.ReadLineAsync();
39
40 Assert.NotNull(response);
41 var result = JsonDocument.Parse(response).RootElement;
42 Assert.True(result.GetProperty("success").GetBoolean());
43 var data = result.GetProperty("data");
44 Assert.True(data.GetArrayLength() > 0);
45 }
46
47 /// <summary>
48 /// Verifies that ListThemes returns a valid JSON array of theme file paths via stdout.
49 /// </summary>
50 [Fact]
51 public async Task ListThemes_ReturnsJsonArray()
52 {
53 _process.SendCommand("""{"actionName":"ListThemes","parameters":{}}""");
54
55 // Theme scanning involves disk I/O; allow extra time
56 string? response = await _process.ReadLineAsync(10000);
57
58 Assert.NotNull(response);
59 var result = JsonDocument.Parse(response).RootElement;
60 Assert.True(result.GetProperty("success").GetBoolean());
61 var data = result.GetProperty("data");
62 Assert.True(data.GetArrayLength() > 0);
63 }
64
65 /// <summary>
66 /// Verifies that multiple sequential query commands each return a separate response.
67 /// </summary>
68 [Fact]
69 public async Task MultipleQueries_EachReturnsResponse()
70 {
71 _process.SendCommand("""{"actionName":"ListAppNames","parameters":{}}""");
72 string? response1 = await _process.ReadLineAsync();
73
74 _process.SendCommand("""{"actionName":"ListThemes","parameters":{}}""");
75 string? response2 = await _process.ReadLineAsync();
76
77 Assert.NotNull(response1);
78 Assert.NotNull(response2);
79 _ = JsonDocument.Parse(response1);
80 _ = JsonDocument.Parse(response2);
81 }
82
83 /// </summary>
84 [Fact]
85 public async Task ListResolutions_ReturnsResponse()
86 {
87 _process.SendCommand("""{"actionName":"ListResolutions","parameters":{}}""");
88
89 string? response = await _process.ReadLineAsync(10000);
90
91 Assert.NotNull(response);
92 Assert.NotEmpty(response);
93 }
94
95 /// <summary>
96 /// Verifies that ListWifiNetworks returns a response via stdout.
97 /// </summary>
98 [Fact]
99 public async Task ListWifiNetworks_ReturnsResponse()
100 {
101 _process.SendCommand("""{"actionName":"ListWifiNetworks","parameters":{}}""");
102
103 string? response = await _process.ReadLineAsync(10000);
104
105 Assert.NotNull(response);
106 Assert.NotEmpty(response);
107 }
108
109 /// <summary>
110 /// Verifies that SetScreenResolution with an invalid value produces a response without crashing.
111 /// Uses an intentionally invalid resolution to avoid changing the actual display.
112 /// </summary>
113 [Fact]
114 public async Task SetScreenResolution_InvalidValue_ReturnsResponse()
115 {
116 _process.SendCommand("""{"actionName":"SetScreenResolution","parameters":{"width":99999,"height":99999}}""");
117
118 // May produce an error message or status — just verify the process survives
119 // and we can still send commands
120 await _process.ReadLineAsync();
121
122 _process.SendCommand("""{"actionName":"ListAppNames","parameters":{}}""");
123 string? response = await _process.ReadLineAsync();
124
125 Assert.False(_process.HasExited);
126 Assert.NotNull(response);
127 }
128
129 // --- Protocol edge cases ---
130
131 /// <summary>
132 /// Verifies that two separate commands each produce a response.
133 /// </summary>
134 [Fact]
135 public async Task MultiCommandObject_ProducesMultipleResponses()
136 {
137 _process.SendCommand("""{"actionName":"ListAppNames","parameters":{}}""");
138 _process.SendCommand("""{"actionName":"ListThemes","parameters":{}}""");
139
140 string? response1 = await _process.ReadLineAsync();
141 string? response2 = await _process.ReadLineAsync(10000);
142
143 Assert.NotNull(response1);
144 Assert.NotNull(response2);
145 _ = JsonDocument.Parse(response1);
146 _ = JsonDocument.Parse(response2);
147 }
148
149 /// <summary>
150 /// Verifies that sending a quit command causes the process to exit.
151 /// </summary>
152 [Fact]
153 public async Task Quit_StopsMidBatch()
154 {
155 _process.SendCommand("""{"actionName":"ListAppNames","parameters":{}}""");
156 string? response1 = await _process.ReadLineAsync();
157 Assert.NotNull(response1);
158 _ = JsonDocument.Parse(response1);
159
160 _process.SendCommand("""{"actionName":"quit","parameters":{}}""");
161 _process.WaitForExit(10000);
162 Assert.True(_process.HasExited);
163 }
164
165 /// <summary>
166 /// Verifies that sending {"quit":""} causes the process to exit cleanly.
167 /// </summary>
168 [Fact]
169 public void Quit_ProcessExits()
170 {
171 _process.SendQuit();
172
173 Assert.True(_process.HasExited);
174 }
175
176 /// <summary>
177 /// Verifies that malformed JSON does not crash the process.
178 /// Sends invalid JSON followed by a valid query to confirm the process is still alive.
179 /// </summary>
180 [Fact]
181 public async Task MalformedJson_ProcessSurvives()
182 {
183 _process.SendCommand("this is not json");
184
185 // Process should still be alive — send a valid command to verify
186 _process.SendCommand("""{"actionName":"ListAppNames","parameters":{}}""");
187 string? response = await _process.ReadLineAsync();
188
189 Assert.False(_process.HasExited);
190 Assert.NotNull(response);
191 }
192
193 /// <summary>
194 /// Verifies that an empty line does not crash the process.
195 /// The error message goes to stdout (known protocol limitation), so we
196 /// consume it before verifying the process is still responsive.
197 /// </summary>
198 [Fact]
199 public async Task EmptyLine_ProcessSurvives()
200 {
201 _process.SendCommand("");
202 // Consume the error/status message that goes to stdout.
203 // Allow extra time since empty-line handling may be slow.
204 string? errorLine = await _process.ReadLineAsync();
205
206 // Ensure the first read completed before starting a second one
207 Assert.False(_process.HasExited);
208
209 _process.SendCommand("""{"actionName":"ListAppNames","parameters":{}}""");
210 string? response = await _process.ReadLineAsync();
211
212 Assert.False(_process.HasExited);
213 Assert.NotNull(response);
214 }
215
216 /// <summary>
217 /// Verifies that an unknown command does not crash the process.
218 /// </summary>
219 [Fact]
220 public async Task UnknownCommand_ProcessSurvives()
221 {
222 _process.SendCommand("""{"actionName":"NonExistentCommand","parameters":{}}""");
223
224 _process.SendCommand("""{"actionName":"ListAppNames","parameters":{}}""");
225 string? response = await _process.ReadLineAsync();
226
227 Assert.False(_process.HasExited);
228 Assert.NotNull(response);
229 }
230
231 /// <summary>
232 /// Verifies that closing stdin (EOF) causes the process to exit cleanly.
233 /// </summary>
234 [Fact]
235 public void StdinClosed_ProcessExits()
236 {
237 _process.CloseStdin();
238 _process.WaitForExit(5000);
239
240 Assert.True(_process.HasExited);
241 }
242
243 // --- Command-line mode ---
244
245 /// <summary>
246 /// Verifies that passing a single JSON command as a command-line argument
247 /// executes it and exits (non-interactive mode).
248 /// </summary>
249 [Fact]
250 public void CommandLineMode_SingleObject_ExecutesAndExits()
251 {
252 var (output, exitCode) = AutoShellProcess.RunWithArgs(
253 """{"actionName":"ListAppNames","parameters":{}}""");
254
255 Assert.Equal(0, exitCode);
256 Assert.NotEmpty(output);
257 _ = JsonDocument.Parse(output.Trim());
258 }
259
260 /// <summary>
261 /// Verifies that passing a JSON array of commands as command-line arguments
262 /// executes all of them and exits.
263 /// </summary>
264 [Fact]
265 public void CommandLineMode_JsonArray_ExecutesAllAndExits()
266 {
267 var (output, exitCode) = AutoShellProcess.RunWithArgs(
268 """[{"actionName":"ListAppNames","parameters":{}},{"actionName":"ListThemes","parameters":{}}]""");
269
270 Assert.Equal(0, exitCode);
271 Assert.NotEmpty(output);
272 }
273}
274