63 lines
2.6 KiB
C#
63 lines
2.6 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Paca.Core.Platform;
|
|
using Xunit;
|
|
|
|
namespace Paca.Tests.Core;
|
|
|
|
/// <summary>
|
|
/// Cycle 5: 극한 RED 시나리오 - 프로세스 실행 시 따옴표 감싸인 ExePath, Null 인자 방어 및 고속 취소 시 스트림 무결성 검증
|
|
/// </summary>
|
|
public class ProcessExecutionExtremeRedTests
|
|
{
|
|
[Fact]
|
|
public async Task Cycle5_Gate1_DesktopProcessRunner_QuotedExePath_MustBeUnquotedAndExecute()
|
|
{
|
|
// Windows 에서 UseShellExecute=false 일 때 ExePath 에 따옴표가 있으면 Win32Exception 발생
|
|
// DesktopProcessRunner 는 따옴표를 자동 정제하여 정상 실행해야 함
|
|
var runner = new DesktopProcessRunner();
|
|
var cmdExe = Environment.GetEnvironmentVariable("ComSpec") ?? "cmd.exe";
|
|
var quotedCmd = $"\"{cmdExe}\"";
|
|
|
|
var spec = new ProcessSpec(quotedCmd, new[] { "/c", "echo", "PACA_DESKTOP_PROCESS_RUNNER_OK" });
|
|
var result = await runner.RunAsync(spec, null, CancellationToken.None);
|
|
|
|
Assert.Equal(0, result.ExitCode);
|
|
Assert.Contains("PACA_DESKTOP_PROCESS_RUNNER_OK", result.Stdout);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Cycle5_Gate2_DesktopProcessRunner_NullArgsInSpec_MustNotThrowArgumentNullException()
|
|
{
|
|
var runner = new DesktopProcessRunner();
|
|
var cmdExe = Environment.GetEnvironmentVariable("ComSpec") ?? "cmd.exe";
|
|
|
|
// 동적 인자 빌더 등에서 전달될 수 있는 null 원소 방어
|
|
var args = new string[] { "/c", "echo", null!, "NULL_ARG_DEFENSE_OK" };
|
|
var spec = new ProcessSpec(cmdExe, args);
|
|
|
|
var result = await runner.RunAsync(spec, null, CancellationToken.None);
|
|
Assert.Equal(0, result.ExitCode);
|
|
Assert.Contains("NULL_ARG_DEFENSE_OK", result.Stdout);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Cycle5_Gate3_DesktopProcessRunner_FastCancellation_MustKillTreeWithoutDisposedStreamFault()
|
|
{
|
|
var runner = new DesktopProcessRunner();
|
|
var cmdExe = Environment.GetEnvironmentVariable("ComSpec") ?? "cmd.exe";
|
|
|
|
// 10초간 대기하는 자식 프로세스
|
|
var spec = new ProcessSpec(cmdExe, new[] { "/c", "ping", "127.0.0.1", "-n", "10" });
|
|
|
|
using var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(50));
|
|
|
|
// 고속 취소 발생 시 ObjectDisposedException 이나 UnobservedTaskException 없이 OperationCanceledException 으로 종료
|
|
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () =>
|
|
{
|
|
await runner.RunAsync(spec, null, cts.Token);
|
|
});
|
|
}
|
|
}
|