From de4ab00080910dd665c4932a4d39028b2eac65b2 Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Fri, 3 Apr 2026 16:22:10 -0700 Subject: [PATCH 01/14] container attach --- .../e2e/WSLCE2EContainerAttachTests.cpp.cpp | 173 ++++++++++++++++++ .../wslc/e2e/WSLCE2EContainerCreateTests.cpp | 61 ------ 2 files changed, 173 insertions(+), 61 deletions(-) create mode 100644 test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp.cpp diff --git a/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp.cpp b/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp.cpp new file mode 100644 index 000000000..f61eb54a1 --- /dev/null +++ b/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp.cpp @@ -0,0 +1,173 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + WSLCE2EContainerAttachTests.cpp + +Abstract: + + This file contains end-to-end tests for WSLC container attach command. +--*/ + +#include "precomp.h" +#include "windows/Common.h" +#include "WSLCExecutor.h" +#include "WSLCE2EHelpers.h" + +namespace WSLCE2ETests { + +class WSLCE2EContainerAttachTests +{ + WSLC_TEST_CLASS(WSLCE2EContainerAttachTests) + + TEST_CLASS_SETUP(ClassSetup) + { + EnsureImageIsLoaded(DebianImage); + return true; + } + + TEST_CLASS_CLEANUP(ClassCleanup) + { + EnsureContainerDoesNotExist(WslcContainerName); + EnsureImageIsDeleted(DebianImage); + return true; + } + + TEST_METHOD_SETUP(TestMethodSetup) + { + EnsureContainerDoesNotExist(WslcContainerName); + return true; + } + + TEST_METHOD(WSLCE2E_Container_Attach_HelpCommand) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(L"container attach --help"); + result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"", .ExitCode = 0}); + } + + TEST_METHOD(WSLCE2E_Container_Attach_TTY) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + const auto& prompt = ">"; + auto result = RunWslc(std::format( + L"container run -itd -e PS1={} --name {} {} bash --norc", prompt, WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + auto containerId = result.GetStdoutOneLine(); + + const auto& expectedAttachPrompt = VT::BuildContainerAttachPrompt(prompt); + const auto& expectedPrompt = VT::BuildContainerPrompt(prompt); + + auto session = RunWslcInteractive(std::format(L"container attach {}", containerId)); + VERIFY_IS_TRUE(session.IsRunning(), L"Container session should be running"); + + // The container attach prompt appears twice. + session.ExpectStdout(expectedAttachPrompt); + session.ExpectStdout(expectedAttachPrompt); + + session.WriteLine("echo hello"); + session.ExpectCommandEcho("echo hello"); + session.ExpectStdout("hello\r\n"); + session.ExpectStdout(expectedPrompt); + + session.WriteLine("whoami"); + session.ExpectCommandEcho("whoami"); + session.ExpectStdout("root\r\n"); + session.ExpectStdout(expectedPrompt); + + session.ExitAndVerifyNoErrors(); + auto exitCode = session.Wait(); + VERIFY_ARE_EQUAL(0, exitCode); + } + + TEST_METHOD(WSLCE2E_Container_Attach_NoTTY) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + auto result = RunWslc(std::format(L"container run -id --name {} {} cat", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + auto containerId = result.GetStdoutOneLine(); + + auto session = RunWslcInteractive(std::format(L"container attach {}", containerId)); + VERIFY_IS_TRUE(session.IsRunning(), L"Container session should be running"); + + session.WriteLine("test line 1"); + session.ExpectStdout("test line 1\n"); + session.WriteLine("test line 2"); + session.ExpectStdout("test line 2\n"); + + // Close stdin to signal EOF to cat + session.CloseStdin(); + + // Wait for cat to exit with code 0 + auto exitCode = session.Wait(10000); + VERIFY_ARE_EQUAL(0, exitCode, L"Cat should exit with code 0 after receiving EOF"); + session.VerifyNoErrors(); + } + + TEST_METHOD(WSLCE2E_Container_Attach_MissingContainerId) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(L"container attach"); + result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"Required argument not provided: 'container-id'\r\n", .ExitCode = 1}); + } + + TEST_METHOD(WSLCE2E_Container_Attach_ContainerNotFound) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container attach {}", WslcContainerName)); + result.Verify({.ExitCode = 1}); + } + +private: + const std::wstring WslcContainerName = L"wslc-test-container"; + const TestImage& DebianImage = DebianTestImage(); + + std::wstring GetHelpMessage() const + { + std::wstringstream output; + output << GetWslcHeader() // + << GetDescription() // + << GetUsage() // + << GetAvailableCommands() // + << GetAvailableOptions(); + return output.str(); + } + + std::wstring GetDescription() const + { + return L"Attaches to a container.\r\n\r\n"; + } + + std::wstring GetUsage() const + { + return L"Usage: wslc container attach [] \r\n\r\n"; + } + + std::wstring GetAvailableCommands() const + { + std::wstringstream commands; + commands << L"The following arguments are available:\r\n" // + << L" container-id Container ID\r\n" // + << L"\r\n"; + return commands.str(); + } + + std::wstring GetAvailableOptions() const + { + std::wstringstream options; + options << L"The following options are available:\r\n" // + << L" --session Specify the session to use\r\n" // + << L" -h,--help Shows help about the selected command\r\n" + << L"\r\n"; + return options.str(); + } +}; +} // namespace WSLCE2ETests \ No newline at end of file diff --git a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp index 9be763ac1..c2a0e4cd9 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp @@ -741,67 +741,6 @@ class WSLCE2EContainerCreateTests session.VerifyNoErrors(); } - TEST_METHOD(WSLCE2E_Container_RunAttach_TTY) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - const auto& prompt = ">"; - auto result = RunWslc(std::format( - L"container run -itd -e PS1={} --name {} {} bash --norc", prompt, WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - auto containerId = result.GetStdoutOneLine(); - - const auto& expectedAttachPrompt = VT::BuildContainerAttachPrompt(prompt); - const auto& expectedPrompt = VT::BuildContainerPrompt(prompt); - - auto session = RunWslcInteractive(std::format(L"container attach {}", containerId)); - VERIFY_IS_TRUE(session.IsRunning(), L"Container session should be running"); - - // The container attach prompt appears twice. - session.ExpectStdout(expectedAttachPrompt); - session.ExpectStdout(expectedAttachPrompt); - - session.WriteLine("echo hello"); - session.ExpectCommandEcho("echo hello"); - session.ExpectStdout("hello\r\n"); - session.ExpectStdout(expectedPrompt); - - session.WriteLine("whoami"); - session.ExpectCommandEcho("whoami"); - session.ExpectStdout("root\r\n"); - session.ExpectStdout(expectedPrompt); - - session.ExitAndVerifyNoErrors(); - auto exitCode = session.Wait(); - VERIFY_ARE_EQUAL(0, exitCode); - } - - TEST_METHOD(WSLCE2E_Container_RunAttach_NoTTY) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - auto result = RunWslc(std::format(L"container run -id --name {} {} cat", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - auto containerId = result.GetStdoutOneLine(); - - auto session = RunWslcInteractive(std::format(L"container attach {}", containerId)); - VERIFY_IS_TRUE(session.IsRunning(), L"Container session should be running"); - - session.WriteLine("test line 1"); - session.ExpectStdout("test line 1\n"); - session.WriteLine("test line 2"); - session.ExpectStdout("test line 2\n"); - - // Close stdin to signal EOF to cat - session.CloseStdin(); - - // Wait for cat to exit with code 0 - auto exitCode = session.Wait(10000); - VERIFY_ARE_EQUAL(0, exitCode, L"Cat should exit with code 0 after receiving EOF"); - session.VerifyNoErrors(); - } - TEST_METHOD(WSLCE2E_Container_ExecInteractive_TTY) { WSL2_TEST_ONLY(); From 62bbf7486b1a6cf8d3388c0730a3b923bd48ee16 Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Sat, 4 Apr 2026 14:54:16 -0700 Subject: [PATCH 02/14] Enhance tests --- .../wslc/e2e/WSLCE2EContainerCreateTests.cpp | 256 +----------------- .../wslc/e2e/WSLCE2EContainerRunTests.cpp | 255 +++++++++++++++++ test/windows/wslc/e2e/WSLCE2EHelpers.cpp | 12 + test/windows/wslc/e2e/WSLCE2EHelpers.h | 2 + test/windows/wslc/e2e/WSLCExecutor.cpp | 14 + test/windows/wslc/e2e/WSLCExecutor.h | 1 + 6 files changed, 291 insertions(+), 249 deletions(-) diff --git a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp index c2a0e4cd9..124f8ce59 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp @@ -387,235 +387,6 @@ class WSLCE2EContainerCreateTests VerifyContainerIsNotListed(WslcContainerName, std::chrono::seconds(2), std::chrono::minutes(1)); } - TEST_METHOD(WSLCE2E_Container_Run_Remove) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - // Run the container with a valid image - auto result = RunWslc(std::format(L"container run --rm --name {} {} echo hello", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - // Run should be deleted on return so no retry. - VerifyContainerIsNotListed(WslcContainerName); - } - - TEST_METHOD(WSLCE2E_Container_Run_EnvOption) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - auto result = RunWslc(std::format( - L"container run --rm --name {} -e {}=A {} env", WslcContainerName, HostEnvVariableName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, std::format(L"{}=A", HostEnvVariableName))); - } - - TEST_METHOD(WSLCE2E_Container_Run_EnvOption_MultipleValues) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - auto result = RunWslc(std::format( - L"container run --rm --name {} -e {}=A -e {}=B {} env", - WslcContainerName, - HostEnvVariableName, - HostEnvVariableName2, - DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, std::format(L"{}=A", HostEnvVariableName))); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, std::format(L"{}=B", HostEnvVariableName2))); - } - - TEST_METHOD(WSLCE2E_Container_Run_EnvOption_KeyOnly_UsesHostValue) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - auto result = RunWslc(std::format( - L"container run --rm --name {} -e {} {} env", WslcContainerName, HostEnvVariableName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); - } - - TEST_METHOD(WSLCE2E_Container_Run_EnvOption_KeyOnly_MultipleValues_UsesHostValues) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - auto result = RunWslc(std::format( - L"container run --rm --name {} -e {} -e {} {} env", - WslcContainerName, - HostEnvVariableName, - HostEnvVariableName2, - DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, std::format(L"{}={}", HostEnvVariableName2, HostEnvVariableValue2))); - } - - TEST_METHOD(WSLCE2E_Container_Run_EnvOption_EmptyValue) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - auto result = RunWslc(std::format( - L"container run --rm --name {} -e {}= {} env", WslcContainerName, HostEnvVariableName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, std::format(L"{}=", HostEnvVariableName))); - } - - TEST_METHOD(WSLCE2E_Container_Run_EnvFile) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - WriteEnvFile(EnvTestFile1, {"WSLC_TEST_ENV_FILE_A=env-file-a", "WSLC_TEST_ENV_FILE_B=env-file-b"}); - - auto result = RunWslc(std::format( - L"container run --rm --name {} --env-file {} {} env", - WslcContainerName, - EscapePath(EnvTestFile1.wstring()), - DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_ENV_FILE_A=env-file-a")); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_ENV_FILE_B=env-file-b")); - } - - TEST_METHOD(WSLCE2E_Container_Run_EnvOption_MixedWithEnvFile) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - WriteEnvFile(EnvTestFile1, {"WSLC_TEST_ENV_MIX_FILE_A=from-file-a", "WSLC_TEST_ENV_MIX_FILE_B=from-file-b"}); - - auto result = RunWslc(std::format( - L"container run --rm --name {} -e WSLC_TEST_ENV_MIX_CLI=from-cli --env-file {} {} env", - WslcContainerName, - EscapePath(EnvTestFile1.wstring()), - DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_ENV_MIX_FILE_A=from-file-a")); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_ENV_MIX_FILE_B=from-file-b")); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_ENV_MIX_CLI=from-cli")); - } - - TEST_METHOD(WSLCE2E_Container_Run_EnvFile_MultipleFiles) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - WriteEnvFile(EnvTestFile1, {"WSLC_TEST_ENV_FILE_MULTI_A=file1-a", "WSLC_TEST_ENV_FILE_MULTI_B=file1-b"}); - - WriteEnvFile(EnvTestFile2, {"WSLC_TEST_ENV_FILE_MULTI_C=file2-c", "WSLC_TEST_ENV_FILE_MULTI_D=file2-d"}); - - auto result = RunWslc(std::format( - L"container run --rm --name {} --env-file {} --env-file {} {} env", - WslcContainerName, - EscapePath(EnvTestFile1.wstring()), - EscapePath(EnvTestFile2.wstring()), - DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_ENV_FILE_MULTI_A=file1-a")); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_ENV_FILE_MULTI_B=file1-b")); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_ENV_FILE_MULTI_C=file2-c")); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_ENV_FILE_MULTI_D=file2-d")); - } - - TEST_METHOD(WSLCE2E_Container_Run_EnvFile_MissingFile) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - auto result = RunWslc(std::format( - L"container run --rm --name {} --env-file ENV_FILE_NOT_FOUND {} env", WslcContainerName, DebianImage.NameAndTag())); - result.Verify( - {.Stderr = L"Environment file 'ENV_FILE_NOT_FOUND' cannot be opened for reading\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1}); - } - - TEST_METHOD(WSLCE2E_Container_Run_EnvFile_InvalidContent) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - WriteEnvFile(EnvTestFile1, {"WSLC_TEST_ENV_VALID=ok", "BAD KEY=value"}); - - auto result = RunWslc(std::format( - L"container run --rm --name {} --env-file {} {} env", - WslcContainerName, - EscapePath(EnvTestFile1.wstring()), - DebianImage.NameAndTag())); - result.Verify({.Stderr = L"Environment variable key 'BAD KEY' cannot contain whitespace\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1}); - } - - TEST_METHOD(WSLCE2E_Container_Run_EnvFile_DuplicateKeys_Precedence) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - WriteEnvFile(EnvTestFile1, {"WSLC_TEST_ENV_DUP=from-file-1"}); - - WriteEnvFile(EnvTestFile2, {"WSLC_TEST_ENV_DUP=from-file-2"}); - - // Later --env-file should win over earlier --env-file for duplicate keys - auto result = RunWslc(std::format( - L"container run --rm --name {} --env-file {} --env-file {} {} env", - WslcContainerName, - EscapePath(EnvTestFile1.wstring()), - EscapePath(EnvTestFile2.wstring()), - DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_ENV_DUP=from-file-2")); - - // Explicit -e should win over env-file value for duplicate keys - result = RunWslc(std::format( - L"container run --rm --name {} -e WSLC_TEST_ENV_DUP=from-cli --env-file {} --env-file {} {} env", - WslcContainerName, - EscapePath(EnvTestFile1.wstring()), - EscapePath(EnvTestFile2.wstring()), - DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_ENV_DUP=from-cli")); - } - - TEST_METHOD(WSLCE2E_Container_Run_EnvFile_ValueContainsEquals) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - WriteEnvFile(EnvTestFile1, {"WSLC_TEST_ENV_EQUALS=value=with=equals"}); - - auto result = RunWslc(std::format( - L"container run --rm --name {} --env-file {} {} env", - WslcContainerName, - EscapePath(EnvTestFile1.wstring()), - DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_ENV_EQUALS=value=with=equals")); - } - TEST_METHOD(WSLCE2E_Container_Exec_EnvOption) { WSL2_TEST_ONLY(); @@ -627,7 +398,7 @@ class WSLCE2EContainerCreateTests result.Verify({.Stderr = L"", .ExitCode = S_OK}); const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, std::format(L"{}=A", HostEnvVariableName))); + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=A", HostEnvVariableName))); } TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_KeyOnly_UsesHostValue) @@ -641,7 +412,7 @@ class WSLCE2EContainerCreateTests result.Verify({.Stderr = L"", .ExitCode = S_OK}); const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); } TEST_METHOD(WSLCE2E_Container_Exec_EnvFile) @@ -657,8 +428,8 @@ class WSLCE2EContainerCreateTests result.Verify({.Stderr = L"", .ExitCode = S_OK}); const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a")); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b")); } TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_MixedWithEnvFile) @@ -675,9 +446,9 @@ class WSLCE2EContainerCreateTests result.Verify({.Stderr = L"", .ExitCode = S_OK}); const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_EXEC_ENV_MIX_FILE_A=from-file-a")); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_EXEC_ENV_MIX_FILE_B=from-file-b")); - VERIFY_IS_TRUE(ContainsOutputLine(outputLines, L"WSLC_TEST_EXEC_ENV_MIX_CLI=from-cli")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_MIX_FILE_A=from-file-a")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_MIX_FILE_B=from-file-b")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_MIX_CLI=from-cli")); } TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_MissingFile) @@ -1063,19 +834,6 @@ class WSLCE2EContainerCreateTests VERIFY_IS_TRUE(envFile.good()); } - bool ContainsOutputLine(const std::vector& outputLines, const std::wstring& expectedLine) const - { - for (const auto& line : outputLines) - { - if (line == expectedLine) - { - return true; - } - } - - return false; - } - std::wstring GetPythonHttpServerScript(uint16_t port) { return std::format(L"python3 -m http.server {}", port); diff --git a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp index 81b1f9797..4ddd6d0f8 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp @@ -25,6 +25,9 @@ class WSLCE2EContainerRunTests TEST_CLASS_SETUP(ClassSetup) { EnsureImageIsLoaded(DebianImage); + + VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName.c_str(), HostEnvVariableValue.c_str())); + VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName2.c_str(), HostEnvVariableValue2.c_str())); return true; } @@ -32,12 +35,25 @@ class WSLCE2EContainerRunTests { EnsureContainerDoesNotExist(WslcContainerName); EnsureImageIsDeleted(DebianImage); + + VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName.c_str(), nullptr)); + VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName2.c_str(), nullptr)); return true; } TEST_METHOD_SETUP(TestMethodSetup) { EnsureContainerDoesNotExist(WslcContainerName); + + EnvTestFile1 = wsl::windows::common::filesystem::GetTempFilename(); + EnvTestFile2 = wsl::windows::common::filesystem::GetTempFilename(); + return true; + } + + TEST_METHOD_CLEANUP(TestMethodCleanup) + { + DeleteFileW(EnvTestFile1.c_str()); + DeleteFileW(EnvTestFile2.c_str()); return true; } @@ -99,10 +115,249 @@ class WSLCE2EContainerRunTests VerifyContainerIsListed(WslcContainerName, L"running"); } + TEST_METHOD(WSLCE2E_Container_Run_Remove) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + // Run the container with a valid image + auto result = RunWslc(std::format(L"container run --rm --name {} {} echo hello", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + // Run should be deleted on return so no retry. + VerifyContainerIsNotListed(WslcContainerName); + } + + TEST_METHOD(WSLCE2E_Container_Run_EnvOption) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + auto result = RunWslc(std::format( + L"container run --rm --name {} -e {}=A {} env", WslcContainerName, HostEnvVariableName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + const auto outputLines = result.GetStdoutLines(); + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=A", HostEnvVariableName))); + } + + TEST_METHOD(WSLCE2E_Container_Run_EnvOption_MultipleValues) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + auto result = RunWslc(std::format( + L"container run --rm --name {} -e {}=A -e {}=B {} env", + WslcContainerName, + HostEnvVariableName, + HostEnvVariableName2, + DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + const auto outputLines = result.GetStdoutLines(); + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=A", HostEnvVariableName))); + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=B", HostEnvVariableName2))); + } + + TEST_METHOD(WSLCE2E_Container_Run_EnvOption_KeyOnly_UsesHostValue) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + auto result = RunWslc(std::format( + L"container run --rm --name {} -e {} {} env", WslcContainerName, HostEnvVariableName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + const auto outputLines = result.GetStdoutLines(); + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); + } + + TEST_METHOD(WSLCE2E_Container_Run_EnvOption_KeyOnly_MultipleValues_UsesHostValues) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + auto result = RunWslc(std::format( + L"container run --rm --name {} -e {} -e {} {} env", + WslcContainerName, + HostEnvVariableName, + HostEnvVariableName2, + DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + const auto outputLines = result.GetStdoutLines(); + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName2, HostEnvVariableValue2))); + } + + TEST_METHOD(WSLCE2E_Container_Run_EnvOption_EmptyValue) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + auto result = RunWslc(std::format( + L"container run --rm --name {} -e {}= {} env", WslcContainerName, HostEnvVariableName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + const auto outputLines = result.GetStdoutLines(); + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=", HostEnvVariableName))); + } + + TEST_METHOD(WSLCE2E_Container_Run_EnvFile) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_FILE_A=env-file-a", "WSLC_TEST_ENV_FILE_B=env-file-b"}); + + auto result = RunWslc(std::format( + L"container run --rm --name {} --env-file {} {} env", + WslcContainerName, + EscapePath(EnvTestFile1.wstring()), + DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + const auto outputLines = result.GetStdoutLines(); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_A=env-file-a")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_B=env-file-b")); + } + + TEST_METHOD(WSLCE2E_Container_Run_EnvOption_MixedWithEnvFile) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_MIX_FILE_A=from-file-a", "WSLC_TEST_ENV_MIX_FILE_B=from-file-b"}); + + auto result = RunWslc(std::format( + L"container run --rm --name {} -e WSLC_TEST_ENV_MIX_CLI=from-cli --env-file {} {} env", + WslcContainerName, + EscapePath(EnvTestFile1.wstring()), + DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + const auto outputLines = result.GetStdoutLines(); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_MIX_FILE_A=from-file-a")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_MIX_FILE_B=from-file-b")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_MIX_CLI=from-cli")); + } + + TEST_METHOD(WSLCE2E_Container_Run_EnvFile_MultipleFiles) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_FILE_MULTI_A=file1-a", "WSLC_TEST_ENV_FILE_MULTI_B=file1-b"}); + + WriteFile(EnvTestFile2, {"WSLC_TEST_ENV_FILE_MULTI_C=file2-c", "WSLC_TEST_ENV_FILE_MULTI_D=file2-d"}); + + auto result = RunWslc(std::format( + L"container run --rm --name {} --env-file {} --env-file {} {} env", + WslcContainerName, + EscapePath(EnvTestFile1.wstring()), + EscapePath(EnvTestFile2.wstring()), + DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + const auto outputLines = result.GetStdoutLines(); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_MULTI_A=file1-a")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_MULTI_B=file1-b")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_MULTI_C=file2-c")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_MULTI_D=file2-d")); + } + + TEST_METHOD(WSLCE2E_Container_Run_EnvFile_MissingFile) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + auto result = RunWslc(std::format( + L"container run --rm --name {} --env-file ENV_FILE_NOT_FOUND {} env", WslcContainerName, DebianImage.NameAndTag())); + result.Verify( + {.Stderr = L"Environment file 'ENV_FILE_NOT_FOUND' cannot be opened for reading\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1}); + } + + TEST_METHOD(WSLCE2E_Container_Run_EnvFile_InvalidContent) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_VALID=ok", "BAD KEY=value"}); + + auto result = RunWslc(std::format( + L"container run --rm --name {} --env-file {} {} env", + WslcContainerName, + EscapePath(EnvTestFile1.wstring()), + DebianImage.NameAndTag())); + result.Verify({.Stderr = L"Environment variable key 'BAD KEY' cannot contain whitespace\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1}); + } + + TEST_METHOD(WSLCE2E_Container_Run_EnvFile_DuplicateKeys_Precedence) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_DUP=from-file-1"}); + + WriteFile(EnvTestFile2, {"WSLC_TEST_ENV_DUP=from-file-2"}); + + // Later --env-file should win over earlier --env-file for duplicate keys + auto result = RunWslc(std::format( + L"container run --rm --name {} --env-file {} --env-file {} {} env", + WslcContainerName, + EscapePath(EnvTestFile1.wstring()), + EscapePath(EnvTestFile2.wstring()), + DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_DUP=from-file-2")); + + // Explicit -e should win over env-file value for duplicate keys + result = RunWslc(std::format( + L"container run --rm --name {} -e WSLC_TEST_ENV_DUP=from-cli --env-file {} --env-file {} {} env", + WslcContainerName, + EscapePath(EnvTestFile1.wstring()), + EscapePath(EnvTestFile2.wstring()), + DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_DUP=from-cli")); + } + + TEST_METHOD(WSLCE2E_Container_Run_EnvFile_ValueContainsEquals) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_EQUALS=value=with=equals"}); + + auto result = RunWslc(std::format( + L"container run --rm --name {} --env-file {} {} env", + WslcContainerName, + EscapePath(EnvTestFile1.wstring()), + DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_EQUALS=value=with=equals")); + } + private: + // Test container name const std::wstring WslcContainerName = L"wslc-test-container"; + + // Test environment variables + const std::wstring HostEnvVariableName = L"WSLC_TEST_HOST_ENV"; + const std::wstring HostEnvVariableName2 = L"WSLC_TEST_HOST_ENV2"; + const std::wstring HostEnvVariableValue = L"wslc-host-env-value"; + const std::wstring HostEnvVariableValue2 = L"wslc-host-env-value2"; + + // Test images const TestImage& DebianImage = DebianTestImage(); + // Test environment variable files + std::filesystem::path EnvTestFile1; + std::filesystem::path EnvTestFile2; + std::wstring GetHelpMessage() const { std::wstringstream output; diff --git a/test/windows/wslc/e2e/WSLCE2EHelpers.cpp b/test/windows/wslc/e2e/WSLCE2EHelpers.cpp index cec283e85..1a87422fa 100644 --- a/test/windows/wslc/e2e/WSLCE2EHelpers.cpp +++ b/test/windows/wslc/e2e/WSLCE2EHelpers.cpp @@ -341,4 +341,16 @@ void EnsureSessionIsTerminated(const std::wstring& sessionName) } } } + +void WriteFile(const std::filesystem::path& filePath, const std::vector& lines) +{ + std::ofstream file(filePath, std::ios::out | std::ios::trunc | std::ios::binary); + VERIFY_IS_TRUE(file.is_open()); + for (const auto& line : lines) + { + file << line << "\n"; + } + + VERIFY_IS_TRUE(file.good()); +} } // namespace WSLCE2ETests \ No newline at end of file diff --git a/test/windows/wslc/e2e/WSLCE2EHelpers.h b/test/windows/wslc/e2e/WSLCE2EHelpers.h index 9a4ea4a7d..17e302653 100644 --- a/test/windows/wslc/e2e/WSLCE2EHelpers.h +++ b/test/windows/wslc/e2e/WSLCE2EHelpers.h @@ -131,6 +131,8 @@ void EnsureImageIsDeleted(const TestImage& image); void EnsureImageContainersAreDeleted(const TestImage& image); void EnsureSessionIsTerminated(const std::wstring& sessionName = L""); +void WriteFile(const std::filesystem::path& filePath, const std::vector& envVariableLines); + // Default timeout of 0 will execute once. template void VerifyContainerIsNotListed( diff --git a/test/windows/wslc/e2e/WSLCExecutor.cpp b/test/windows/wslc/e2e/WSLCExecutor.cpp index ba855dfd5..3472d4eba 100644 --- a/test/windows/wslc/e2e/WSLCExecutor.cpp +++ b/test/windows/wslc/e2e/WSLCExecutor.cpp @@ -127,6 +127,20 @@ std::wstring WSLCExecutionResult::GetStdoutOneLine() const return stdoutLines[0]; } +bool WSLCExecutionResult::StdoutContainsLine(const std::wstring& expectedLine) const +{ + VERIFY_IS_TRUE(Stdout.has_value()); + for (const auto& line : GetStdoutLines()) + { + if (line == expectedLine) + { + return true; + } + } + + return false; +} + WSLCExecutionResult RunWslc(const std::wstring& commandLine, ElevationType elevationType) { auto cmd = L"\"" + GetWslcPath() + L"\" " + commandLine; diff --git a/test/windows/wslc/e2e/WSLCExecutor.h b/test/windows/wslc/e2e/WSLCExecutor.h index 2c3c54ea2..5f1612f71 100644 --- a/test/windows/wslc/e2e/WSLCExecutor.h +++ b/test/windows/wslc/e2e/WSLCExecutor.h @@ -43,6 +43,7 @@ struct WSLCExecutionResult void Verify(const WSLCExecutionResult& expected) const; std::vector GetStdoutLines() const; std::wstring GetStdoutOneLine() const; + bool StdoutContainsLine(const std::wstring& expectedLine) const; }; // Interactive session for testing wslc commands that require stdin/stdout interaction. From f0fc76a00e90fcb6e2a51754e09798b315306c89 Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Sat, 4 Apr 2026 23:39:29 -0700 Subject: [PATCH 03/14] Move more tests to run --- .../wslc/e2e/WSLCE2EContainerCreateTests.cpp | 184 +----------------- .../wslc/e2e/WSLCE2EContainerRunTests.cpp | 164 ++++++++++++++++ test/windows/wslc/e2e/WSLCE2EHelpers.cpp | 5 + test/windows/wslc/e2e/WSLCE2EHelpers.h | 1 + 4 files changed, 172 insertions(+), 182 deletions(-) diff --git a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp index dd2751129..20c5d8698 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp @@ -32,16 +32,10 @@ class WSLCE2EContainerCreateTests { EnsureImageIsLoaded(AlpineImage); EnsureImageIsLoaded(DebianImage); - EnsureImageIsLoaded(PythonImage); VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName.c_str(), HostEnvVariableValue.c_str())); VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName2.c_str(), HostEnvVariableValue2.c_str())); VERIFY_IS_TRUE(::SetEnvironmentVariableW(MissingHostEnvVariableName.c_str(), nullptr)); - - // Initialize Winsock for loopback connectivity tests - WSADATA wsaData{}; - const int result = WSAStartup(MAKEWORD(2, 2), &wsaData); - THROW_HR_IF(HRESULT_FROM_WIN32(result), result != 0); return true; } @@ -50,14 +44,10 @@ class WSLCE2EContainerCreateTests EnsureContainerDoesNotExist(WslcContainerName); EnsureImageIsDeleted(AlpineImage); EnsureImageIsDeleted(DebianImage); - EnsureImageIsDeleted(PythonImage); VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName.c_str(), nullptr)); VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName2.c_str(), nullptr)); VERIFY_IS_TRUE(::SetEnvironmentVariableW(MissingHostEnvVariableName.c_str(), nullptr)); - - // Cleanup Winsock - WSACleanup(); return true; } @@ -419,7 +409,7 @@ class WSLCE2EContainerCreateTests { WSL2_TEST_ONLY(); - WriteEnvFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a", "WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b"}); + WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a", "WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = S_OK}); @@ -436,7 +426,7 @@ class WSLCE2EContainerCreateTests { WSL2_TEST_ONLY(); - WriteEnvFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_MIX_FILE_A=from-file-a", "WSLC_TEST_EXEC_ENV_MIX_FILE_B=from-file-b"}); + WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_MIX_FILE_A=from-file-a", "WSLC_TEST_EXEC_ENV_MIX_FILE_B=from-file-b"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = S_OK}); @@ -463,55 +453,6 @@ class WSLCE2EContainerCreateTests {.Stderr = L"Environment file 'ENV_FILE_NOT_FOUND' cannot be opened for reading\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_RunInteractive_TTY) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - const auto& prompt = ">"; - auto session = RunWslcInteractive( - std::format(L"container run -it -e PS1={} --name {} {} bash --norc", prompt, WslcContainerName, DebianImage.NameAndTag())); - VERIFY_IS_TRUE(session.IsRunning(), L"Container session should be running"); - - const auto& expectedPrompt = VT::BuildContainerPrompt(prompt); - session.ExpectStdout(expectedPrompt); - - session.WriteLine("echo hello"); - session.ExpectCommandEcho("echo hello"); - session.ExpectStdout("hello\r\n"); - session.ExpectStdout(expectedPrompt); - - session.WriteLine("whoami"); - session.ExpectCommandEcho("whoami"); - session.ExpectStdout("root\r\n"); - session.ExpectStdout(expectedPrompt); - - auto exitCode = session.ExitAndVerifyNoErrors(); - VERIFY_ARE_EQUAL(0, exitCode); - } - - TEST_METHOD(WSLCE2E_Container_RunInteractive_NoTTY) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - auto session = RunWslcInteractive(std::format(L"container run -i --name {} {} cat", WslcContainerName, DebianImage.NameAndTag())); - VERIFY_IS_TRUE(session.IsRunning(), L"Container session should be running"); - - session.WriteLine("test line 1"); - session.ExpectStdout("test line 1\n"); - session.WriteLine("test line 2"); - session.ExpectStdout("test line 2\n"); - - // Close stdin to signal EOF to cat - session.CloseStdin(); - - // Wait for cat to exit with code 0 - auto exitCode = session.Wait(10000); - VERIFY_ARE_EQUAL(0, exitCode, L"Cat should exit with code 0 after receiving EOF"); - session.VerifyNoErrors(); - } - TEST_METHOD(WSLCE2E_Container_ExecInteractive_TTY) { WSL2_TEST_ONLY(); @@ -645,105 +586,6 @@ class WSLCE2EContainerCreateTests result.Verify({.Stdout = L"lifecycle works\n", .Stderr = L"", .ExitCode = ExpectedExitCode}); } - TEST_METHOD(WSLCE2E_Container_Run_Port_TCP) - { - WSL2_TEST_ONLY(); - - // Start a container with a simple server listening on a port - auto result = RunWslc(std::format( - L"container run -d --name {} -p {}:{} {} {}", - WslcContainerName, - HostTestPort1, - ContainerTestPort, - PythonImage.NameAndTag(), - GetPythonHttpServerScript(ContainerTestPort))); - result.Verify({.Stderr = L"", .ExitCode = 0}); - - // Verify we can connect to the server from the host side - ExpectHttpResponse(std::format(L"http://127.0.0.1:{}", HostTestPort1).c_str(), HTTP_STATUS_OK, true); - - // Verify the port mapping is correct in the container inspect data - auto inspectContainer = InspectContainer(WslcContainerName); - auto portKey = std::to_string(ContainerTestPort) + "/tcp"; - VERIFY_IS_TRUE(inspectContainer.Ports.contains(portKey)); - - auto portBindings = inspectContainer.Ports[portKey]; - VERIFY_ARE_EQUAL(1u, portBindings.size()); - VERIFY_ARE_EQUAL(std::to_string(HostTestPort1), portBindings[0].HostPort); - VERIFY_ARE_EQUAL("127.0.0.1", portBindings[0].HostIp); - } - - TEST_METHOD(WSLCE2E_Container_Run_PortMultipleMappings) - { - WSL2_TEST_ONLY(); - - // Start a container with a simple server listening on a port - // Map two host ports to the same container port - auto result = RunWslc(std::format( - L"container run -d --name {} -p {}:{} -p {}:{} {} {}", - WslcContainerName, - HostTestPort1, - ContainerTestPort, - HostTestPort2, - ContainerTestPort, - PythonImage.NameAndTag(), - GetPythonHttpServerScript(ContainerTestPort))); - result.Verify({.Stderr = L"", .ExitCode = 0}); - - // From the host side, verify we can connect to both ports - ExpectHttpResponse(std::format(L"http://127.0.0.1:{}", HostTestPort1).c_str(), HTTP_STATUS_OK, true); - ExpectHttpResponse(std::format(L"http://127.0.0.1:{}", HostTestPort2).c_str(), HTTP_STATUS_OK, true); - } - - TEST_METHOD(WSLCE2E_Container_Run_PortAlreadyInUse) - { - // Bug: https://github.com/microsoft/WSL/issues/14448 - SKIP_TEST_NOT_IMPL(); - - WSL2_TEST_ONLY(); - - // Start a container with a simple server listening on a port - auto result1 = RunWslc(std::format( - L"container run -d --name {} -p {}:{} {} {}", - WslcContainerName, - HostTestPort1, - ContainerTestPort, - PythonImage.NameAndTag(), - GetPythonHttpServerScript(ContainerTestPort))); - result1.Verify({.Stderr = L"", .ExitCode = 0}); - - // Attempt to start another container mapping the same host port - auto result2 = RunWslc(std::format(L"container run -p {}:{} {}", HostTestPort1, ContainerTestPort, DebianImage.NameAndTag())); - result2.Verify({.ExitCode = 1}); - } - - // https://github.com/microsoft/WSL/issues/14433 - TEST_METHOD(WSLCE2E_Container_Run_PortEphemeral_NotSupported) - { - WSL2_TEST_ONLY(); - - auto result = RunWslc(std::format(L"container run -p 80 {}", DebianImage.NameAndTag())); - result.Verify({.Stderr = L"Port mappings with ephemeral host ports, specific host IPs, or UDP protocol are not currently supported\r\nError code: ERROR_NOT_SUPPORTED\r\n", .ExitCode = 1}); - } - - // https://github.com/microsoft/WSL/issues/14433 - TEST_METHOD(WSLCE2E_Container_Run_PortUdp_NotSupported) - { - WSL2_TEST_ONLY(); - - auto result = RunWslc(std::format(L"container run -p 80:80/udp {}", DebianImage.NameAndTag())); - result.Verify({.Stderr = L"Port mappings with ephemeral host ports, specific host IPs, or UDP protocol are not currently supported\r\nError code: ERROR_NOT_SUPPORTED\r\n", .ExitCode = 1}); - } - - // https://github.com/microsoft/WSL/issues/14433 - TEST_METHOD(WSLCE2E_Container_Run_PortHostIP_NotSupported) - { - WSL2_TEST_ONLY(); - - auto result = RunWslc(std::format(L"container run -p 127.0.0.1:80:80 {}", DebianImage.NameAndTag())); - result.Verify({.Stderr = L"Port mappings with ephemeral host ports, specific host IPs, or UDP protocol are not currently supported\r\nError code: ERROR_NOT_SUPPORTED\r\n", .ExitCode = 1}); - } - TEST_METHOD(WSLCE2E_Container_Create_UserOption_UidRoot) { WSL2_TEST_ONLY(); @@ -832,14 +674,8 @@ class WSLCE2EContainerCreateTests // Test images const TestImage& AlpineImage = AlpineTestImage(); const TestImage& DebianImage = DebianTestImage(); - const TestImage& PythonImage = PythonTestImage(); const TestImage& InvalidImage = InvalidTestImage(); - // Test ports - const uint16_t ContainerTestPort = 8080; - const uint16_t HostTestPort1 = 1234; - const uint16_t HostTestPort2 = 1235; - // Test volume files std::filesystem::path VolumeTestFile1; std::filesystem::path VolumeTestFile2; @@ -894,21 +730,5 @@ class WSLCE2EContainerCreateTests << L"\r\n"; return options.str(); } - - void WriteEnvFile(const std::filesystem::path& filePath, const std::vector& envVariableLines) const - { - std::ofstream envFile(filePath, std::ios::out | std::ios::trunc | std::ios::binary); - VERIFY_IS_TRUE(envFile.is_open()); - for (const auto& line : envVariableLines) - { - envFile << line << "\n"; - } - VERIFY_IS_TRUE(envFile.good()); - } - - std::wstring GetPythonHttpServerScript(uint16_t port) - { - return std::format(L"python3 -m http.server {}", port); - } }; } // namespace WSLCE2ETests \ No newline at end of file diff --git a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp index d8909f07f..35d2bacef 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp @@ -25,9 +25,15 @@ class WSLCE2EContainerRunTests TEST_CLASS_SETUP(ClassSetup) { EnsureImageIsLoaded(DebianImage); + EnsureImageIsLoaded(PythonImage); VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName.c_str(), HostEnvVariableValue.c_str())); VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName2.c_str(), HostEnvVariableValue2.c_str())); + + // Initialize Winsock for loopback connectivity tests + WSADATA wsaData{}; + const int result = WSAStartup(MAKEWORD(2, 2), &wsaData); + THROW_HR_IF(HRESULT_FROM_WIN32(result), result != 0); return true; } @@ -35,9 +41,13 @@ class WSLCE2EContainerRunTests { EnsureContainerDoesNotExist(WslcContainerName); EnsureImageIsDeleted(DebianImage); + EnsureImageIsDeleted(PythonImage); VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName.c_str(), nullptr)); VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName2.c_str(), nullptr)); + + // Cleanup Winsock + WSACleanup(); return true; } @@ -399,6 +409,154 @@ class WSLCE2EContainerRunTests result.Verify({.Stdout = L"nobody\n65534\n65534\n", .Stderr = L"", .ExitCode = 0}); } + TEST_METHOD(WSLCE2E_Container_Run_PortMultipleMappings) + { + WSL2_TEST_ONLY(); + + // Start a container with a simple server listening on a port + // Map two host ports to the same container port + auto result = RunWslc(std::format( + L"container run -d --name {} -p {}:{} -p {}:{} {} {}", + WslcContainerName, + HostTestPort1, + ContainerTestPort, + HostTestPort2, + ContainerTestPort, + PythonImage.NameAndTag(), + GetPythonHttpServerScript(ContainerTestPort))); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + // From the host side, verify we can connect to both ports + ExpectHttpResponse(std::format(L"http://127.0.0.1:{}", HostTestPort1).c_str(), HTTP_STATUS_OK, true); + ExpectHttpResponse(std::format(L"http://127.0.0.1:{}", HostTestPort2).c_str(), HTTP_STATUS_OK, true); + } + + TEST_METHOD(WSLCE2E_Container_Run_PortAlreadyInUse) + { + // Bug: https://github.com/microsoft/WSL/issues/14448 + SKIP_TEST_NOT_IMPL(); + + WSL2_TEST_ONLY(); + + // Start a container with a simple server listening on a port + auto result1 = RunWslc(std::format( + L"container run -d --name {} -p {}:{} {} {}", + WslcContainerName, + HostTestPort1, + ContainerTestPort, + PythonImage.NameAndTag(), + GetPythonHttpServerScript(ContainerTestPort))); + result1.Verify({.Stderr = L"", .ExitCode = 0}); + + // Attempt to start another container mapping the same host port + auto result2 = RunWslc(std::format(L"container run -p {}:{} {}", HostTestPort1, ContainerTestPort, DebianImage.NameAndTag())); + result2.Verify({.ExitCode = 1}); + } + + // https://github.com/microsoft/WSL/issues/14433 + TEST_METHOD(WSLCE2E_Container_Run_PortEphemeral_NotSupported) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -p 80 {}", DebianImage.NameAndTag())); + result.Verify({.Stderr = L"Port mappings with ephemeral host ports, specific host IPs, or UDP protocol are not currently supported\r\nError code: ERROR_NOT_SUPPORTED\r\n", .ExitCode = 1}); + } + + // https://github.com/microsoft/WSL/issues/14433 + TEST_METHOD(WSLCE2E_Container_Run_PortUdp_NotSupported) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -p 80:80/udp {}", DebianImage.NameAndTag())); + result.Verify({.Stderr = L"Port mappings with ephemeral host ports, specific host IPs, or UDP protocol are not currently supported\r\nError code: ERROR_NOT_SUPPORTED\r\n", .ExitCode = 1}); + } + + // https://github.com/microsoft/WSL/issues/14433 + TEST_METHOD(WSLCE2E_Container_Run_PortHostIP_NotSupported) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -p 127.0.0.1:80:80 {}", DebianImage.NameAndTag())); + result.Verify({.Stderr = L"Port mappings with ephemeral host ports, specific host IPs, or UDP protocol are not currently supported\r\nError code: ERROR_NOT_SUPPORTED\r\n", .ExitCode = 1}); + } + + TEST_METHOD(WSLCE2E_Container_Run_Port_TCP) + { + WSL2_TEST_ONLY(); + + // Start a container with a simple server listening on a port + auto result = RunWslc(std::format( + L"container run -d --name {} -p {}:{} {} {}", + WslcContainerName, + HostTestPort1, + ContainerTestPort, + PythonImage.NameAndTag(), + GetPythonHttpServerScript(ContainerTestPort))); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + // Verify we can connect to the server from the host side + ExpectHttpResponse(std::format(L"http://127.0.0.1:{}", HostTestPort1).c_str(), HTTP_STATUS_OK, true); + + // Verify the port mapping is correct in the container inspect data + auto inspectContainer = InspectContainer(WslcContainerName); + auto portKey = std::to_string(ContainerTestPort) + "/tcp"; + VERIFY_IS_TRUE(inspectContainer.Ports.contains(portKey)); + + auto portBindings = inspectContainer.Ports[portKey]; + VERIFY_ARE_EQUAL(1u, portBindings.size()); + VERIFY_ARE_EQUAL(std::to_string(HostTestPort1), portBindings[0].HostPort); + VERIFY_ARE_EQUAL("127.0.0.1", portBindings[0].HostIp); + } + + TEST_METHOD(WSLCE2E_Container_Run_Interactive_TTY) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + const auto& prompt = ">"; + auto session = RunWslcInteractive( + std::format(L"container run -it -e PS1={} --name {} {} bash --norc", prompt, WslcContainerName, DebianImage.NameAndTag())); + VERIFY_IS_TRUE(session.IsRunning(), L"Container session should be running"); + + const auto& expectedPrompt = VT::BuildContainerPrompt(prompt); + session.ExpectStdout(expectedPrompt); + + session.WriteLine("echo hello"); + session.ExpectCommandEcho("echo hello"); + session.ExpectStdout("hello\r\n"); + session.ExpectStdout(expectedPrompt); + + session.WriteLine("whoami"); + session.ExpectCommandEcho("whoami"); + session.ExpectStdout("root\r\n"); + session.ExpectStdout(expectedPrompt); + + auto exitCode = session.ExitAndVerifyNoErrors(); + VERIFY_ARE_EQUAL(0, exitCode); + } + + TEST_METHOD(WSLCE2E_Container_Run_Interactive_NoTTY) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + auto session = RunWslcInteractive(std::format(L"container run -i --name {} {} cat", WslcContainerName, DebianImage.NameAndTag())); + VERIFY_IS_TRUE(session.IsRunning(), L"Container session should be running"); + + session.WriteLine("test line 1"); + session.ExpectStdout("test line 1\n"); + session.WriteLine("test line 2"); + session.ExpectStdout("test line 2\n"); + + // Close stdin to signal EOF to cat + session.CloseStdin(); + + // Wait for cat to exit with code 0 + auto exitCode = session.Wait(10000); + VERIFY_ARE_EQUAL(0, exitCode, L"Cat should exit with code 0 after receiving EOF"); + session.VerifyNoErrors(); + } + private: // Test container name const std::wstring WslcContainerName = L"wslc-test-container"; @@ -411,11 +569,17 @@ class WSLCE2EContainerRunTests // Test images const TestImage& DebianImage = DebianTestImage(); + const TestImage& PythonImage = PythonTestImage(); // Test environment variable files std::filesystem::path EnvTestFile1; std::filesystem::path EnvTestFile2; + // Test ports + const uint16_t ContainerTestPort = 8080; + const uint16_t HostTestPort1 = 1234; + const uint16_t HostTestPort2 = 1235; + std::wstring GetHelpMessage() const { std::wstringstream output; diff --git a/test/windows/wslc/e2e/WSLCE2EHelpers.cpp b/test/windows/wslc/e2e/WSLCE2EHelpers.cpp index 1a87422fa..8e4f7a3c9 100644 --- a/test/windows/wslc/e2e/WSLCE2EHelpers.cpp +++ b/test/windows/wslc/e2e/WSLCE2EHelpers.cpp @@ -353,4 +353,9 @@ void WriteFile(const std::filesystem::path& filePath, const std::vector& envVariableLines); +std::wstring GetPythonHttpServerScript(uint16_t port); // Default timeout of 0 will execute once. template From d8b211faa5ffd876e7bf9722bf8983e8395d588c Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Sun, 5 Apr 2026 00:09:05 -0700 Subject: [PATCH 04/14] Init exec --- .../wslc/e2e/WSLCE2EContainerCreateTests.cpp | 167 ------ .../wslc/e2e/WSLCE2EContainerExecTests.cpp | 504 ++++++++++++++++++ 2 files changed, 504 insertions(+), 167 deletions(-) create mode 100644 test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp diff --git a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp index 20c5d8698..e180264ca 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp @@ -377,140 +377,6 @@ class WSLCE2EContainerCreateTests VerifyContainerIsNotListed(WslcContainerName, std::chrono::seconds(2), std::chrono::minutes(1)); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvOption) - { - WSL2_TEST_ONLY(); - - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - result = RunWslc(std::format(L"container exec -e {}=A {} env", HostEnvVariableName, WslcContainerName)); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=A", HostEnvVariableName))); - } - - TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_KeyOnly_UsesHostValue) - { - WSL2_TEST_ONLY(); - - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - result = RunWslc(std::format(L"container exec -e {} {} env", HostEnvVariableName, WslcContainerName)); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); - } - - TEST_METHOD(WSLCE2E_Container_Exec_EnvFile) - { - WSL2_TEST_ONLY(); - - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a", "WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b"}); - - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - result = RunWslc(std::format(L"container exec --env-file {} {} env", EscapePath(EnvTestFile1.wstring()), WslcContainerName)); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a")); - VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b")); - } - - TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_MixedWithEnvFile) - { - WSL2_TEST_ONLY(); - - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_MIX_FILE_A=from-file-a", "WSLC_TEST_EXEC_ENV_MIX_FILE_B=from-file-b"}); - - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - result = RunWslc(std::format( - L"container exec -e WSLC_TEST_EXEC_ENV_MIX_CLI=from-cli --env-file {} {} env", EscapePath(EnvTestFile1.wstring()), WslcContainerName)); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - const auto outputLines = result.GetStdoutLines(); - VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_MIX_FILE_A=from-file-a")); - VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_MIX_FILE_B=from-file-b")); - VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_MIX_CLI=from-cli")); - } - - TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_MissingFile) - { - WSL2_TEST_ONLY(); - - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - result = RunWslc(std::format(L"container exec --env-file ENV_FILE_NOT_FOUND {} env", WslcContainerName)); - result.Verify( - {.Stderr = L"Environment file 'ENV_FILE_NOT_FOUND' cannot be opened for reading\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1}); - } - - TEST_METHOD(WSLCE2E_Container_ExecInteractive_TTY) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - - const auto& prompt = ">"; - auto result = - RunWslc(std::format(L"container run -itd -e PS1={} --name {} {}", prompt, WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - auto containerId = result.GetStdoutOneLine(); - - const auto& expectedPrompt = VT::BuildContainerPrompt(prompt); - - auto session = RunWslcInteractive(std::format(L"container exec -it {} /bin/bash --norc", containerId)); - VERIFY_IS_TRUE(session.IsRunning(), L"Container session should be running"); - - session.ExpectStdout(expectedPrompt); - - session.WriteLine("echo hello"); - session.ExpectCommandEcho("echo hello"); - session.ExpectStdout("hello\r\n"); - session.ExpectStdout(expectedPrompt); - - session.WriteLine("whoami"); - session.ExpectCommandEcho("whoami"); - session.ExpectStdout("root\r\n"); - session.ExpectStdout(expectedPrompt); - - session.ExitAndVerifyNoErrors(); - auto exitCode = session.Wait(); - VERIFY_ARE_EQUAL(0, exitCode); - } - - TEST_METHOD(WSLCE2E_Container_ExecInteractive_NoTTY) - { - WSL2_TEST_ONLY(); - VerifyContainerIsNotListed(WslcContainerName); - auto result = RunWslc(std::format(L"container run -id --name {} {}", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - auto containerId = result.GetStdoutOneLine(); - - auto session = RunWslcInteractive(std::format(L"container exec -i {} cat", containerId)); - VERIFY_IS_TRUE(session.IsRunning(), L"Container session should be running"); - - session.WriteLine("test line 1"); - session.ExpectStdout("test line 1\n"); - session.WriteLine("test line 2"); - session.ExpectStdout("test line 2\n"); - - // Close stdin to signal EOF to cat - session.CloseStdin(); - - // Wait for cat to exit with code 0 - auto exitCode = session.Wait(10000); - VERIFY_ARE_EQUAL(0, exitCode, L"Cat should exit with code 0 after receiving EOF"); - session.VerifyNoErrors(); - } - TEST_METHOD(WSLCE2E_Container_CreateStartAttach_TTY) { WSL2_TEST_ONLY(); @@ -623,39 +489,6 @@ class WSLCE2EContainerCreateTests {.Stderr = L"unable to find user user_does_not_exist: no matching entries in passwd file\r\nError code: E_FAIL\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Exec_UserOption_UidRoot) - { - WSL2_TEST_ONLY(); - - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - result = RunWslc(std::format(L"container exec -u 0 {} sh -c \"id -u; id -g\"", WslcContainerName)); - result.Verify({.Stdout = L"0\n0\n", .Stderr = L"", .ExitCode = S_OK}); - } - - TEST_METHOD(WSLCE2E_Container_Exec_UserOption_NameGroupRoot) - { - WSL2_TEST_ONLY(); - - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - result = RunWslc(std::format(L"container exec -u root:root {} sh -c \"id -un; id -u; id -g\"", WslcContainerName)); - result.Verify({.Stdout = L"root\n0\n0\n", .Stderr = L"", .ExitCode = S_OK}); - } - - TEST_METHOD(WSLCE2E_Container_Exec_UserOption_InvalidGroup_Fails) - { - WSL2_TEST_ONLY(); - - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); - - result = RunWslc(std::format(L"container exec -u root:badgid {} id -u", WslcContainerName)); - result.Verify({.Stdout = L"unable to find group badgid: no matching entries in group file\r\n", .ExitCode = 126}); - } - private: // Test container name const std::wstring WslcContainerName = L"wslc-test-container"; diff --git a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp new file mode 100644 index 000000000..026460460 --- /dev/null +++ b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp @@ -0,0 +1,504 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + WSLCE2EContainerExecTests.cpp + +Abstract: + + This file contains end-to-end tests for WSLC container exec command. +--*/ + +#include "precomp.h" +#include "windows/Common.h" +#include "WSLCExecutor.h" +#include "WSLCE2EHelpers.h" + +namespace WSLCE2ETests { + +class WSLCE2EContainerExecTests +{ + WSLC_TEST_CLASS(WSLCE2EContainerExecTests) + + TEST_CLASS_SETUP(ClassSetup) + { + VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName.c_str(), HostEnvVariableValue.c_str())); + VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName2.c_str(), HostEnvVariableValue2.c_str())); + VERIFY_IS_TRUE(::SetEnvironmentVariableW(MissingHostEnvVariableName.c_str(), nullptr)); + + EnsureImageIsLoaded(DebianImage); + return true; + } + + TEST_CLASS_CLEANUP(ClassCleanup) + { + EnsureContainerDoesNotExist(WslcContainerName); + EnsureImageIsDeleted(DebianImage); + + VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName.c_str(), nullptr)); + VERIFY_IS_TRUE(::SetEnvironmentVariableW(HostEnvVariableName2.c_str(), nullptr)); + VERIFY_IS_TRUE(::SetEnvironmentVariableW(MissingHostEnvVariableName.c_str(), nullptr)); + return true; + } + + TEST_METHOD_SETUP(TestMethodSetup) + { + EnvTestFile1 = wsl::windows::common::filesystem::GetTempFilename(); + EnvTestFile2 = wsl::windows::common::filesystem::GetTempFilename(); + EnsureContainerDoesNotExist(WslcContainerName); + return true; + } + + TEST_METHOD_CLEANUP(TestMethodCleanup) + { + DeleteFileW(EnvTestFile1.c_str()); + DeleteFileW(EnvTestFile2.c_str()); + return true; + } + + TEST_METHOD(WSLCE2E_Container_Exec_HelpCommand) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(L"container exec --help"); + result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"", .ExitCode = 0}); + } + + TEST_METHOD(WSLCE2E_Container_Exec_MissingContainerId) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(L"container exec"); + result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"Required argument not provided: 'container-id'\r\n", .ExitCode = 1}); + } + + TEST_METHOD(WSLCE2E_Container_Exec_MissingCommand) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + result = RunWslc(std::format(L"container exec {}", WslcContainerName)); + result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"Required argument not provided: 'command'\r\n", .ExitCode = 1}); + } + + TEST_METHOD(WSLCE2E_Container_Exec_ContainerNotFound) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container exec {} echo hello", WslcContainerName)); + result.Verify({.Stderr = L"Element not found. \r\nError code: ERROR_NOT_FOUND\r\n", .ExitCode = 1}); + } + + TEST_METHOD(WSLCE2E_Container_Exec_SimpleCommand) + { + WSL2_TEST_ONLY(); + + // Run a container in background + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + // Execute a command + result = RunWslc(std::format(L"container exec {} echo hello", WslcContainerName)); + result.Verify({.Stdout = L"hello\n", .Stderr = L"", .ExitCode = 0}); + } + + TEST_METHOD(WSLCE2E_Container_Exec_InteractiveTTY) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + + const auto& prompt = ">"; + auto result = + RunWslc(std::format(L"container run -itd -e PS1={} --name {} {}", prompt, WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + auto containerId = result.GetStdoutOneLine(); + + const auto& expectedPrompt = VT::BuildContainerPrompt(prompt); + + auto session = RunWslcInteractive(std::format(L"container exec -it {} /bin/bash --norc", containerId)); + VERIFY_IS_TRUE(session.IsRunning(), L"Container session should be running"); + + session.ExpectStdout(expectedPrompt); + + session.WriteLine("echo hello"); + session.ExpectCommandEcho("echo hello"); + session.ExpectStdout("hello\r\n"); + session.ExpectStdout(expectedPrompt); + + session.WriteLine("whoami"); + session.ExpectCommandEcho("whoami"); + session.ExpectStdout("root\r\n"); + session.ExpectStdout(expectedPrompt); + + session.ExitAndVerifyNoErrors(); + auto exitCode = session.Wait(); + VERIFY_ARE_EQUAL(0, exitCode); + } + + TEST_METHOD(WSLCE2E_Container_Exec_InteractiveNoTTY) + { + WSL2_TEST_ONLY(); + VerifyContainerIsNotListed(WslcContainerName); + auto result = RunWslc(std::format(L"container run -id --name {} {}", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + auto containerId = result.GetStdoutOneLine(); + + auto session = RunWslcInteractive(std::format(L"container exec -i {} cat", containerId)); + VERIFY_IS_TRUE(session.IsRunning(), L"Container session should be running"); + + session.WriteLine("test line 1"); + session.ExpectStdout("test line 1\n"); + session.WriteLine("test line 2"); + session.ExpectStdout("test line 2\n"); + + // Close stdin to signal EOF to cat + session.CloseStdin(); + + // Wait for cat to exit with code 0 + auto exitCode = session.Wait(10000); + VERIFY_ARE_EQUAL(0, exitCode, L"Cat should exit with code 0 after receiving EOF"); + session.VerifyNoErrors(); + } + + TEST_METHOD(WSLCE2E_Container_Exec_EnvOption) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + result = RunWslc(std::format(L"container exec -e {}=A {} env", HostEnvVariableName, WslcContainerName)); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + const auto outputLines = result.GetStdoutLines(); + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=A", HostEnvVariableName))); + } + + TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_KeyOnly_UsesHostValue) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + result = RunWslc(std::format(L"container exec -e {} {} env", HostEnvVariableName, WslcContainerName)); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + const auto outputLines = result.GetStdoutLines(); + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); + } + + TEST_METHOD(WSLCE2E_Container_Exec_EnvFile) + { + WSL2_TEST_ONLY(); + + WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a", "WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b"}); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + result = RunWslc(std::format(L"container exec --env-file {} {} env", EscapePath(EnvTestFile1.wstring()), WslcContainerName)); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + const auto outputLines = result.GetStdoutLines(); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b")); + } + + + TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_MultipleValues) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + result = RunWslc(std::format( + L"container exec -e {}=value-a -e {}=value-b {} env", + HostEnvVariableName, + HostEnvVariableName2, + WslcContainerName)); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=value-a", HostEnvVariableName))); + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=value-b", HostEnvVariableName2))); + } + + TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_KeyOnly_MultipleValues_UsesHostValues) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + result = RunWslc(std::format( + L"container exec -e {} -e {} {} env", + HostEnvVariableName, + HostEnvVariableName2, + WslcContainerName)); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName2, HostEnvVariableValue2))); + } + + TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_EmptyValue) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + // Pass an explicit empty value and verify it is present as KEY= + result = RunWslc(std::format(L"container exec -e {}= {} env", HostEnvVariableName, WslcContainerName)); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=", HostEnvVariableName))); + } + + TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_MixedWithEnvFile) + { + WSL2_TEST_ONLY(); + + WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_MIX_FILE_A=from-file-a", "WSLC_TEST_EXEC_ENV_MIX_FILE_B=from-file-b"}); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + result = RunWslc(std::format( + L"container exec -e WSLC_TEST_EXEC_ENV_MIX_CLI=from-cli --env-file {} {} env", EscapePath(EnvTestFile1.wstring()), WslcContainerName)); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_MIX_FILE_A=from-file-a")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_MIX_FILE_B=from-file-b")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_MIX_CLI=from-cli")); + } + + TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_MissingFile) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + result = RunWslc(std::format(L"container exec --env-file ENV_FILE_NOT_FOUND {} env", WslcContainerName)); + result.Verify( + {.Stderr = L"Environment file 'ENV_FILE_NOT_FOUND' cannot be opened for reading\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1}); + } + + TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_MultipleFiles) + { + WSL2_TEST_ONLY(); + + WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_FILE_MULTI_A=file1-a", "WSLC_TEST_EXEC_ENV_FILE_MULTI_B=file1-b"}); + WriteFile(EnvTestFile2, {"WSLC_TEST_EXEC_ENV_FILE_MULTI_C=file2-c", "WSLC_TEST_EXEC_ENV_FILE_MULTI_D=file2-d"}); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + result = RunWslc(std::format( + L"container exec --env-file {} --env-file {} {} env", + EscapePath(EnvTestFile1.wstring()), + EscapePath(EnvTestFile2.wstring()), + WslcContainerName)); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_MULTI_A=file1-a")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_MULTI_B=file1-b")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_MULTI_C=file2-c")); + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_MULTI_D=file2-d")); + } + + TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_InvalidContent) + { + WSL2_TEST_ONLY(); + + WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_VALID=ok", "BAD KEY=value"}); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + result = RunWslc(std::format(L"container exec --env-file {} {} env", EscapePath(EnvTestFile1.wstring()), WslcContainerName)); + result.Verify({.Stderr = L"Environment variable key 'BAD KEY' cannot contain whitespace\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1}); + } + + TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_DuplicateKeys_Precedence) + { + WSL2_TEST_ONLY(); + + WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_DUP=from-file-1"}); + WriteFile(EnvTestFile2, {"WSLC_TEST_EXEC_ENV_DUP=from-file-2"}); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + // Later --env-file wins + result = RunWslc(std::format( + L"container exec --env-file {} --env-file {} {} env", + EscapePath(EnvTestFile1.wstring()), + EscapePath(EnvTestFile2.wstring()), + WslcContainerName)); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_DUP=from-file-2")); + + // Explicit -e wins over env-file + result = RunWslc(std::format( + L"container exec -e WSLC_TEST_EXEC_ENV_DUP=from-cli --env-file {} --env-file {} {} env", + EscapePath(EnvTestFile1.wstring()), + EscapePath(EnvTestFile2.wstring()), + WslcContainerName)); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_DUP=from-cli")); + } + + TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_ValueContainsEquals) + { + WSL2_TEST_ONLY(); + + WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_EQUALS=value=with=equals"}); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + result = RunWslc(std::format(L"container exec --env-file {} {} env", EscapePath(EnvTestFile1.wstring()), WslcContainerName)); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_EQUALS=value=with=equals")); + } + + TEST_METHOD(WSLCE2E_Container_Exec_ExitCode_Propagates) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + result = RunWslc(std::format(L"container exec {} sh -c \"exit 42\"", WslcContainerName)); + result.Verify({.Stdout = L"", .Stderr = L"", .ExitCode = 42}); + } + + TEST_METHOD(WSLCE2E_Container_Exec_Stderr_Propagates) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + result = RunWslc(std::format(L"container exec {} sh -c \"echo exec-error 1>&2\"", WslcContainerName)); + result.Verify({.Stdout = L"", .Stderr = L"exec-error\n", .ExitCode = 0}); + } + + TEST_METHOD(WSLCE2E_Container_Exec_StoppedContainer) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run --name {} {} echo hello", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = 0}); + + result = RunWslc(std::format(L"container exec {} echo should-fail", WslcContainerName)); + result.Verify({.Stderr = L"The group or resource is not in the correct state to perform the requested operation. \r\nError code: ERROR_INVALID_STATE\r\n", .ExitCode = 1}); + } + + TEST_METHOD(WSLCE2E_Container_Exec_UserOption_UidRoot) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + result = RunWslc(std::format(L"container exec -u 0 {} sh -c \"id -u; id -g\"", WslcContainerName)); + result.Verify({.Stdout = L"0\n0\n", .Stderr = L"", .ExitCode = S_OK}); + } + + TEST_METHOD(WSLCE2E_Container_Exec_UserOption_NameGroupRoot) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + result = RunWslc(std::format(L"container exec -u root:root {} sh -c \"id -un; id -u; id -g\"", WslcContainerName)); + result.Verify({.Stdout = L"root\n0\n0\n", .Stderr = L"", .ExitCode = S_OK}); + } + + TEST_METHOD(WSLCE2E_Container_Exec_UserOption_InvalidGroup_Fails) + { + WSL2_TEST_ONLY(); + + auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); + result.Verify({.Stderr = L"", .ExitCode = S_OK}); + + result = RunWslc(std::format(L"container exec -u root:badgid {} id -u", WslcContainerName)); + result.Verify({.Stdout = L"unable to find group badgid: no matching entries in group file\r\n", .ExitCode = 126}); + } + +private: + const std::wstring WslcContainerName = L"wslc-test-container"; + const TestImage& DebianImage = DebianTestImage(); + + // Test environment variables + const std::wstring HostEnvVariableName = L"WSLC_TEST_HOST_ENV"; + const std::wstring HostEnvVariableName2 = L"WSLC_TEST_HOST_ENV2"; + const std::wstring HostEnvVariableValue = L"wslc-host-env-value"; + const std::wstring HostEnvVariableValue2 = L"wslc-host-env-value2"; + const std::wstring MissingHostEnvVariableName = L"WSLC_TEST_MISSING_HOST_ENV"; + + // Test environment variable files + std::filesystem::path EnvTestFile1; + std::filesystem::path EnvTestFile2; + + std::wstring GetHelpMessage() const + { + std::wstringstream output; + output << GetWslcHeader() // + << GetDescription() // + << GetUsage() // + << GetAvailableCommands() // + << GetAvailableOptions(); + return output.str(); + } + + std::wstring GetDescription() const + { + return L"Executes a command in a running container.\r\n\r\n"; + } + + std::wstring GetUsage() const + { + return L"Usage: wslc container exec [] [...]\r\n\r\n"; + } + + std::wstring GetAvailableCommands() const + { + std::wstringstream commands; + commands << L"The following arguments are available:\r\n" + << L" container-id Container ID\r\n" + << L" command The command to run\r\n" + << L" arguments Arguments to pass to the command being executed inside the container\r\n" + << L"\r\n"; + return commands.str(); + } + + std::wstring GetAvailableOptions() const + { + std::wstringstream options; + options << L"The following options are available:\r\n" + << L" -d,--detach Run container in detached mode\r\n" + << L" -e,--env Key=Value pairs for environment variables\r\n" + << L" --env-file File containing key=value pairs of env variables\r\n" + << L" -i,--interactive Attach to stdin and keep it open\r\n" + << L" --session Specify the session to use\r\n" + << L" -t,--tty Open a TTY with the container process.\r\n" + << L" -u,--user User ID for the process (name|uid|uid:gid)\r\n" + << L" -h,--help Shows help about the selected command\r\n" + << L"\r\n"; + return options.str(); + } +}; +} // namespace WSLCE2ETests \ No newline at end of file From cc91ca916b620b0d9543d97edec3d6608d77e124 Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Sun, 5 Apr 2026 00:09:34 -0700 Subject: [PATCH 05/14] Clang format --- .../e2e/WSLCE2EContainerAttachTests.cpp.cpp | 2 +- .../wslc/e2e/WSLCE2EContainerExecTests.cpp | 22 ++++--------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp.cpp b/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp.cpp index f61eb54a1..5060d9d7f 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp.cpp @@ -163,7 +163,7 @@ class WSLCE2EContainerAttachTests std::wstring GetAvailableOptions() const { std::wstringstream options; - options << L"The following options are available:\r\n" // + options << L"The following options are available:\r\n" // << L" --session Specify the session to use\r\n" // << L" -h,--help Shows help about the selected command\r\n" << L"\r\n"; diff --git a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp index 026460460..8b451fe37 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp @@ -209,7 +209,6 @@ class WSLCE2EContainerExecTests VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b")); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_MultipleValues) { WSL2_TEST_ONLY(); @@ -218,10 +217,7 @@ class WSLCE2EContainerExecTests result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(std::format( - L"container exec -e {}=value-a -e {}=value-b {} env", - HostEnvVariableName, - HostEnvVariableName2, - WslcContainerName)); + L"container exec -e {}=value-a -e {}=value-b {} env", HostEnvVariableName, HostEnvVariableName2, WslcContainerName)); result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=value-a", HostEnvVariableName))); @@ -235,11 +231,7 @@ class WSLCE2EContainerExecTests auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); - result = RunWslc(std::format( - L"container exec -e {} -e {} {} env", - HostEnvVariableName, - HostEnvVariableName2, - WslcContainerName)); + result = RunWslc(std::format(L"container exec -e {} -e {} {} env", HostEnvVariableName, HostEnvVariableName2, WslcContainerName)); result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); @@ -301,10 +293,7 @@ class WSLCE2EContainerExecTests result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(std::format( - L"container exec --env-file {} --env-file {} {} env", - EscapePath(EnvTestFile1.wstring()), - EscapePath(EnvTestFile2.wstring()), - WslcContainerName)); + L"container exec --env-file {} --env-file {} {} env", EscapePath(EnvTestFile1.wstring()), EscapePath(EnvTestFile2.wstring()), WslcContainerName)); result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_MULTI_A=file1-a")); @@ -338,10 +327,7 @@ class WSLCE2EContainerExecTests // Later --env-file wins result = RunWslc(std::format( - L"container exec --env-file {} --env-file {} {} env", - EscapePath(EnvTestFile1.wstring()), - EscapePath(EnvTestFile2.wstring()), - WslcContainerName)); + L"container exec --env-file {} --env-file {} {} env", EscapePath(EnvTestFile1.wstring()), EscapePath(EnvTestFile2.wstring()), WslcContainerName)); result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_DUP=from-file-2")); From bac0a6f2316a3762b42c86e2ed9a493cac37ee15 Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Mon, 6 Apr 2026 09:58:22 -0700 Subject: [PATCH 06/14] Resolve copilot comment --- ...ttachTests.cpp.cpp => WSLCE2EContainerAttachTests.cpp} | 0 test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp | 8 -------- 2 files changed, 8 deletions(-) rename test/windows/wslc/e2e/{WSLCE2EContainerAttachTests.cpp.cpp => WSLCE2EContainerAttachTests.cpp} (100%) diff --git a/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp.cpp b/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp similarity index 100% rename from test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp.cpp rename to test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp diff --git a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp index 35d2bacef..7e3a51caa 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp @@ -147,7 +147,6 @@ class WSLCE2EContainerRunTests L"container run --rm --name {} -e {}=A {} env", WslcContainerName, HostEnvVariableName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = S_OK}); - const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=A", HostEnvVariableName))); } @@ -164,7 +163,6 @@ class WSLCE2EContainerRunTests DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = S_OK}); - const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=A", HostEnvVariableName))); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=B", HostEnvVariableName2))); } @@ -178,7 +176,6 @@ class WSLCE2EContainerRunTests L"container run --rm --name {} -e {} {} env", WslcContainerName, HostEnvVariableName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = S_OK}); - const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); } @@ -195,7 +192,6 @@ class WSLCE2EContainerRunTests DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = S_OK}); - const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName2, HostEnvVariableValue2))); } @@ -209,7 +205,6 @@ class WSLCE2EContainerRunTests L"container run --rm --name {} -e {}= {} env", WslcContainerName, HostEnvVariableName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = S_OK}); - const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=", HostEnvVariableName))); } @@ -227,7 +222,6 @@ class WSLCE2EContainerRunTests DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = S_OK}); - const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_A=env-file-a")); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_B=env-file-b")); } @@ -246,7 +240,6 @@ class WSLCE2EContainerRunTests DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = S_OK}); - const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_MIX_FILE_A=from-file-a")); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_MIX_FILE_B=from-file-b")); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_MIX_CLI=from-cli")); @@ -269,7 +262,6 @@ class WSLCE2EContainerRunTests DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = S_OK}); - const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_MULTI_A=file1-a")); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_MULTI_B=file1-b")); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_MULTI_C=file2-c")); From 6a4a03324ae016192751767b6be0d7c17b169ac4 Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Mon, 6 Apr 2026 10:01:40 -0700 Subject: [PATCH 07/14] Replace S_OK with 0 --- .../wslc/e2e/WSLCE2EContainerAttachTests.cpp | 4 +- .../wslc/e2e/WSLCE2EContainerCreateTests.cpp | 30 ++++----- .../wslc/e2e/WSLCE2EContainerExecTests.cpp | 32 ++++----- .../wslc/e2e/WSLCE2EContainerRunTests.cpp | 24 +++---- .../wslc/e2e/WSLCE2EContainerTests.cpp | 2 +- test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp | 66 +++++++++---------- 6 files changed, 79 insertions(+), 79 deletions(-) diff --git a/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp index 5060d9d7f..5fa370428 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp @@ -57,7 +57,7 @@ class WSLCE2EContainerAttachTests const auto& prompt = ">"; auto result = RunWslc(std::format( L"container run -itd -e PS1={} --name {} {} bash --norc", prompt, WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); auto containerId = result.GetStdoutOneLine(); const auto& expectedAttachPrompt = VT::BuildContainerAttachPrompt(prompt); @@ -90,7 +90,7 @@ class WSLCE2EContainerAttachTests WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); auto result = RunWslc(std::format(L"container run -id --name {} {} cat", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); auto containerId = result.GetStdoutOneLine(); auto session = RunWslcInteractive(std::format(L"container attach {}", containerId)); diff --git a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp index e180264ca..6f19b0ed7 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp @@ -74,7 +74,7 @@ class WSLCE2EContainerCreateTests { WSL2_TEST_ONLY(); auto result = RunWslc(L"container create --help"); - result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"", .ExitCode = 0}); } TEST_METHOD(WSLCE2E_Container_Create_MissingImage) @@ -103,7 +103,7 @@ class WSLCE2EContainerCreateTests // Create the container with a valid image auto result = RunWslc(std::format(L"container create --name {} {}", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); std::wstring containerId = result.GetStdoutOneLine(); // Verify the container is listed with the correct status @@ -117,7 +117,7 @@ class WSLCE2EContainerCreateTests // Create the container with a valid image auto result = RunWslc(std::format(L"container create --name {} {}", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); auto containerId = result.GetStdoutOneLine(); // Attempt to create another container with the same name @@ -146,7 +146,7 @@ class WSLCE2EContainerCreateTests hostDirectory.wstring(), AlpineImage.NameAndTag(), fileName)); - result.Verify({.Stdout = L"WSLC Volume Test", .Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stdout = L"WSLC Volume Test", .Stderr = L"", .ExitCode = 0}); } TEST_METHOD(WSLCE2E_Container_Create_Volume_WriteFromContainerReadFromHost_ReadWritePermissionByDefault) @@ -161,7 +161,7 @@ class WSLCE2EContainerCreateTests hostDirectory.wstring(), AlpineImage.NameAndTag(), fileName)); - result.Verify({.Stdout = L"", .Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stdout = L"", .Stderr = L"", .ExitCode = 0}); // Read all file content auto content = ReadFileContent(VolumeTestFile1.wstring()); @@ -180,7 +180,7 @@ class WSLCE2EContainerCreateTests hostDirectory.wstring(), AlpineImage.NameAndTag(), fileName)); - result.Verify({.Stdout = L"", .Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stdout = L"", .Stderr = L"", .ExitCode = 0}); // Read all file content std::wifstream in(VolumeTestFile1); @@ -367,11 +367,11 @@ class WSLCE2EContainerCreateTests VerifyContainerIsNotListed(WslcContainerName); auto result = RunWslc(std::format(L"container create --rm --name {} {} echo hello", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Start the container. result = RunWslc(std::format(L"container start {}", WslcContainerName)); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify with retry timeout of 1 minute. VerifyContainerIsNotListed(WslcContainerName, std::chrono::seconds(2), std::chrono::minutes(1)); @@ -385,7 +385,7 @@ class WSLCE2EContainerCreateTests const auto& prompt = ">"; auto result = RunWslc(std::format( L"container create -it -e PS1={} --name {} {} bash --norc", prompt, WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); auto containerId = result.GetStdoutOneLine(); const auto& expectedPrompt = VT::BuildContainerPrompt(prompt); @@ -415,7 +415,7 @@ class WSLCE2EContainerCreateTests WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); auto result = RunWslc(std::format(L"container create -i --name {} {} cat", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); auto containerId = result.GetStdoutOneLine(); // Start with attach @@ -446,7 +446,7 @@ class WSLCE2EContainerCreateTests auto result = RunWslc(std::format( L"container create --name {} {} sh -c \"echo lifecycle works; exit {}\"", WslcContainerName, AlpineImage.NameAndTag(), ExpectedExitCode)); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(std::format(L"container start -a {}", WslcContainerName)); result.Verify({.Stdout = L"lifecycle works\n", .Stderr = L"", .ExitCode = ExpectedExitCode}); @@ -458,10 +458,10 @@ class WSLCE2EContainerCreateTests auto result = RunWslc( std::format(L"container create --name {} -u 0 {} sh -c \"id -u; id -g\"", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(std::format(L"container start -a {}", WslcContainerName)); - result.Verify({.Stdout = L"0\n0\n", .Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stdout = L"0\n0\n", .Stderr = L"", .ExitCode = 0}); } TEST_METHOD(WSLCE2E_Container_Create_UserOption_NameGroupRoot) @@ -470,10 +470,10 @@ class WSLCE2EContainerCreateTests auto result = RunWslc(std::format( L"container create --name {} -u root:root {} sh -c \"id -un; id -u; id -g\"", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(std::format(L"container start -a {}", WslcContainerName)); - result.Verify({.Stdout = L"root\n0\n0\n", .Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stdout = L"root\n0\n0\n", .Stderr = L"", .ExitCode = 0}); } TEST_METHOD(WSLCE2E_Container_Create_UserOption_UnknownUser_Fails) diff --git a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp index 8b451fe37..b7caaba5d 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp @@ -114,7 +114,7 @@ class WSLCE2EContainerExecTests const auto& prompt = ">"; auto result = RunWslc(std::format(L"container run -itd -e PS1={} --name {} {}", prompt, WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); auto containerId = result.GetStdoutOneLine(); const auto& expectedPrompt = VT::BuildContainerPrompt(prompt); @@ -144,7 +144,7 @@ class WSLCE2EContainerExecTests WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); auto result = RunWslc(std::format(L"container run -id --name {} {}", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); auto containerId = result.GetStdoutOneLine(); auto session = RunWslcInteractive(std::format(L"container exec -i {} cat", containerId)); @@ -169,10 +169,10 @@ class WSLCE2EContainerExecTests WSL2_TEST_ONLY(); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(std::format(L"container exec -e {}=A {} env", HostEnvVariableName, WslcContainerName)); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=A", HostEnvVariableName))); @@ -183,10 +183,10 @@ class WSLCE2EContainerExecTests WSL2_TEST_ONLY(); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(std::format(L"container exec -e {} {} env", HostEnvVariableName, WslcContainerName)); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); @@ -199,10 +199,10 @@ class WSLCE2EContainerExecTests WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a", "WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(std::format(L"container exec --env-file {} {} env", EscapePath(EnvTestFile1.wstring()), WslcContainerName)); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a")); @@ -259,11 +259,11 @@ class WSLCE2EContainerExecTests WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_MIX_FILE_A=from-file-a", "WSLC_TEST_EXEC_ENV_MIX_FILE_B=from-file-b"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(std::format( L"container exec -e WSLC_TEST_EXEC_ENV_MIX_CLI=from-cli --env-file {} {} env", EscapePath(EnvTestFile1.wstring()), WslcContainerName)); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_MIX_FILE_A=from-file-a")); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_MIX_FILE_B=from-file-b")); @@ -275,7 +275,7 @@ class WSLCE2EContainerExecTests WSL2_TEST_ONLY(); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(std::format(L"container exec --env-file ENV_FILE_NOT_FOUND {} env", WslcContainerName)); result.Verify( @@ -396,10 +396,10 @@ class WSLCE2EContainerExecTests WSL2_TEST_ONLY(); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(std::format(L"container exec -u 0 {} sh -c \"id -u; id -g\"", WslcContainerName)); - result.Verify({.Stdout = L"0\n0\n", .Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stdout = L"0\n0\n", .Stderr = L"", .ExitCode = 0}); } TEST_METHOD(WSLCE2E_Container_Exec_UserOption_NameGroupRoot) @@ -407,10 +407,10 @@ class WSLCE2EContainerExecTests WSL2_TEST_ONLY(); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(std::format(L"container exec -u root:root {} sh -c \"id -un; id -u; id -g\"", WslcContainerName)); - result.Verify({.Stdout = L"root\n0\n0\n", .Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stdout = L"root\n0\n0\n", .Stderr = L"", .ExitCode = 0}); } TEST_METHOD(WSLCE2E_Container_Exec_UserOption_InvalidGroup_Fails) @@ -418,7 +418,7 @@ class WSLCE2EContainerExecTests WSL2_TEST_ONLY(); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(std::format(L"container exec -u root:badgid {} id -u", WslcContainerName)); result.Verify({.Stdout = L"unable to find group badgid: no matching entries in group file\r\n", .ExitCode = 126}); diff --git a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp index 7e3a51caa..74c0ac78f 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp @@ -132,7 +132,7 @@ class WSLCE2EContainerRunTests // Run the container with a valid image auto result = RunWslc(std::format(L"container run --rm --name {} {} echo hello", WslcContainerName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Run should be deleted on return so no retry. VerifyContainerIsNotListed(WslcContainerName); @@ -145,7 +145,7 @@ class WSLCE2EContainerRunTests auto result = RunWslc(std::format( L"container run --rm --name {} -e {}=A {} env", WslcContainerName, HostEnvVariableName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=A", HostEnvVariableName))); } @@ -161,7 +161,7 @@ class WSLCE2EContainerRunTests HostEnvVariableName, HostEnvVariableName2, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=A", HostEnvVariableName))); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=B", HostEnvVariableName2))); @@ -174,7 +174,7 @@ class WSLCE2EContainerRunTests auto result = RunWslc(std::format( L"container run --rm --name {} -e {} {} env", WslcContainerName, HostEnvVariableName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); } @@ -190,7 +190,7 @@ class WSLCE2EContainerRunTests HostEnvVariableName, HostEnvVariableName2, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName2, HostEnvVariableValue2))); @@ -203,7 +203,7 @@ class WSLCE2EContainerRunTests auto result = RunWslc(std::format( L"container run --rm --name {} -e {}= {} env", WslcContainerName, HostEnvVariableName, DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=", HostEnvVariableName))); } @@ -220,7 +220,7 @@ class WSLCE2EContainerRunTests WslcContainerName, EscapePath(EnvTestFile1.wstring()), DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_A=env-file-a")); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_B=env-file-b")); @@ -238,7 +238,7 @@ class WSLCE2EContainerRunTests WslcContainerName, EscapePath(EnvTestFile1.wstring()), DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_MIX_FILE_A=from-file-a")); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_MIX_FILE_B=from-file-b")); @@ -260,7 +260,7 @@ class WSLCE2EContainerRunTests EscapePath(EnvTestFile1.wstring()), EscapePath(EnvTestFile2.wstring()), DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_MULTI_A=file1-a")); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_MULTI_B=file1-b")); @@ -310,7 +310,7 @@ class WSLCE2EContainerRunTests EscapePath(EnvTestFile1.wstring()), EscapePath(EnvTestFile2.wstring()), DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_DUP=from-file-2")); @@ -321,7 +321,7 @@ class WSLCE2EContainerRunTests EscapePath(EnvTestFile1.wstring()), EscapePath(EnvTestFile2.wstring()), DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_DUP=from-cli")); } @@ -338,7 +338,7 @@ class WSLCE2EContainerRunTests WslcContainerName, EscapePath(EnvTestFile1.wstring()), DebianImage.NameAndTag())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_EQUALS=value=with=equals")); } diff --git a/test/windows/wslc/e2e/WSLCE2EContainerTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerTests.cpp index d9d54c6ec..e5d90c361 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerTests.cpp @@ -37,7 +37,7 @@ class WSLCE2EContainerTests TEST_METHOD(WSLCE2E_Container_HelpCommand) { WSL2_TEST_ONLY(); - RunWslc(L"container --help").Verify({.Stdout = GetHelpMessage(), .Stderr = L"", .ExitCode = S_OK}); + RunWslc(L"container --help").Verify({.Stdout = GetHelpMessage(), .Stderr = L"", .ExitCode = 0}); } TEST_METHOD(WSLCE2E_Container_InvalidCommand_DisplaysErrorMessage) diff --git a/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp b/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp index c4486ffc7..29ba072ce 100644 --- a/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp @@ -57,11 +57,11 @@ class WSLCE2EGlobalTests // Run container list to create the default elevated session auto result = RunWslc(L"container list", ElevationType::Elevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify session list shows the admin session name result = RunWslc(L"session list", ElevationType::Elevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.Stdout.has_value()); VERIFY_IS_TRUE(result.Stdout->find(L"wslc-cli-admin") != std::wstring::npos); @@ -73,11 +73,11 @@ class WSLCE2EGlobalTests // Run container list non-elevated to create the default non-elevated session auto result = RunWslc(L"container list", ElevationType::NonElevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify session list shows the non-admin session name result = RunWslc(L"session list", ElevationType::NonElevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.Stdout.has_value()); @@ -91,7 +91,7 @@ class WSLCE2EGlobalTests // First ensure admin session is created by running container list. auto result = RunWslc(L"container list", ElevationType::Elevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Try to explicitly target the admin session from non-elevated process result = RunWslc(L"container list --session wslc-cli-admin", ElevationType::NonElevated); @@ -106,13 +106,13 @@ class WSLCE2EGlobalTests // First ensure non-elevated session is created by running container list. auto result = RunWslc(L"container list", ElevationType::NonElevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Elevated user should be able to explicitly target the non-admin session result = RunWslc(L"container list --session wslc-cli", ElevationType::Elevated); // This should work - elevated users can access non-elevated sessions - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); } TEST_METHOD(WSLCE2E_Session_CreateMixedElevation_Fails) @@ -137,21 +137,21 @@ class WSLCE2EGlobalTests // Run container list to create the default session if it does not already exist auto result = RunWslc(L"container list"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify session list shows the admin session name result = RunWslc(L"session list"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.Stdout.has_value()); VERIFY_IS_TRUE(result.Stdout->find(L"wslc-cli-admin") != std::wstring::npos); // Terminate the session result = RunWslc(L"session terminate"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify session no longer shows up result = RunWslc(L"session list"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.Stdout.has_value()); VERIFY_IS_FALSE(result.Stdout->find(L"wslc-cli-admin") != std::wstring::npos); @@ -159,21 +159,21 @@ class WSLCE2EGlobalTests // Run container list to create the default session if it does not already exist result = RunWslc(L"container list", ElevationType::NonElevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify session list shows the non-elevated session name result = RunWslc(L"session list"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.Stdout.has_value()); VERIFY_IS_TRUE(result.Stdout->find(L"wslc-cli\r\n") != std::wstring::npos); // Terminate the session result = RunWslc(L"session terminate", ElevationType::NonElevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify session no longer shows up result = RunWslc(L"session list"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.Stdout.has_value()); VERIFY_IS_FALSE(result.Stdout->find(L"wslc-cli\r\n") != std::wstring::npos); } @@ -184,21 +184,21 @@ class WSLCE2EGlobalTests // Run container list to create the default session if it does not already exist auto result = RunWslc(L"container list"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify session list shows the admin session name result = RunWslc(L"session list"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.Stdout.has_value()); VERIFY_IS_TRUE(result.Stdout->find(L"wslc-cli-admin") != std::wstring::npos); // Terminate the session result = RunWslc(L"session terminate wslc-cli-admin"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify session no longer shows up result = RunWslc(L"session list"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.Stdout.has_value()); VERIFY_IS_FALSE(result.Stdout->find(L"wslc-cli-admin") != std::wstring::npos); @@ -206,21 +206,21 @@ class WSLCE2EGlobalTests // Run container list to create the default session if it does not already exist result = RunWslc(L"container list", ElevationType::NonElevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify session list shows the non-elevated session name result = RunWslc(L"session list"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.Stdout.has_value()); VERIFY_IS_TRUE(result.Stdout->find(L"wslc-cli\r\n") != std::wstring::npos); // Terminate the session result = RunWslc(L"session terminate wslc-cli", ElevationType::NonElevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify session no longer shows up result = RunWslc(L"session list"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.Stdout.has_value()); VERIFY_IS_FALSE(result.Stdout->find(L"wslc-cli\r\n") != std::wstring::npos); } @@ -231,13 +231,13 @@ class WSLCE2EGlobalTests // Run container list to create the default sessions if they do not already exist. auto result = RunWslc(L"container list", ElevationType::Elevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(L"container list", ElevationType::NonElevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify session list shows both sessions. result = RunWslc(L"session list"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.Stdout.has_value()); VERIFY_IS_TRUE(result.Stdout->find(L"wslc-cli-admin") != std::wstring::npos); VERIFY_IS_TRUE(result.Stdout->find(L"wslc-cli\r\n") != std::wstring::npos); @@ -248,11 +248,11 @@ class WSLCE2EGlobalTests // Terminate the non-elevated session from the elevated process. result = RunWslc(L"session terminate wslc-cli", ElevationType::Elevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify non-elevated session no longer shows up result = RunWslc(L"session list"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); VERIFY_IS_TRUE(result.Stdout.has_value()); VERIFY_IS_FALSE(result.Stdout->find(L"wslc-cli\r\n") != std::wstring::npos); } @@ -279,7 +279,7 @@ class WSLCE2EGlobalTests // Verify session list result = RunWslc(L"session list"); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Verify there is a session with the name of the test session in the session list output. VERIFY_IS_TRUE(result.Stdout.has_value()); @@ -288,13 +288,13 @@ class WSLCE2EGlobalTests // Run container list in the test session, which should succeed if the session is valid. result = RunWslc(std::format(L"container list --session {}", session.Name())); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); // Add a container to the new session. result = RunWslc( std::format(L"container create --session {} --name {} {}", session.Name(), L"test-cont", DebianTestImage().NameAndTag())); result.Dump(); // Dump so it is easier to find any potential issues with the pull in the test output. - result.Verify({.ExitCode = S_OK}); + result.Verify({.ExitCode = 0}); // Verify container exists in the custom session VerifyContainerIsListed(L"test-cont", L"created", session.Name()); @@ -309,9 +309,9 @@ class WSLCE2EGlobalTests // Ensure sessions are created by running container list elevated and non-elevated. auto result = RunWslc(L"container list", ElevationType::NonElevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); result = RunWslc(L"container list", ElevationType::Elevated); - result.Verify({.Stderr = L"", .ExitCode = S_OK}); + result.Verify({.Stderr = L"", .ExitCode = 0}); { Log::Comment(L"Testing elevated interactive session"); From 880e7022b5afa6c939e4e7650d4cb95d8e63c66a Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Mon, 6 Apr 2026 10:10:22 -0700 Subject: [PATCH 08/14] Added error messages --- test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp index 5fa370428..9506d6f20 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp @@ -123,7 +123,7 @@ class WSLCE2EContainerAttachTests WSL2_TEST_ONLY(); auto result = RunWslc(std::format(L"container attach {}", WslcContainerName)); - result.Verify({.ExitCode = 1}); + result.Verify({.Stderr = L"Element not found. \r\nError code: ERROR_NOT_FOUND\r\n", .ExitCode = 1}); } private: From f3e11b8c2d6dc030c995ca19d9f96403a02894ea Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Mon, 6 Apr 2026 10:22:36 -0700 Subject: [PATCH 09/14] Resolve copilot comment --- test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp index b7caaba5d..6463ef0c2 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp @@ -174,7 +174,6 @@ class WSLCE2EContainerExecTests result = RunWslc(std::format(L"container exec -e {}=A {} env", HostEnvVariableName, WslcContainerName)); result.Verify({.Stderr = L"", .ExitCode = 0}); - const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=A", HostEnvVariableName))); } @@ -188,7 +187,6 @@ class WSLCE2EContainerExecTests result = RunWslc(std::format(L"container exec -e {} {} env", HostEnvVariableName, WslcContainerName)); result.Verify({.Stderr = L"", .ExitCode = 0}); - const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); } @@ -204,7 +202,6 @@ class WSLCE2EContainerExecTests result = RunWslc(std::format(L"container exec --env-file {} {} env", EscapePath(EnvTestFile1.wstring()), WslcContainerName)); result.Verify({.Stderr = L"", .ExitCode = 0}); - const auto outputLines = result.GetStdoutLines(); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a")); VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b")); } From 532648f213704237a0579c0311fa2c1cc263572b Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Mon, 6 Apr 2026 12:43:56 -0700 Subject: [PATCH 10/14] Clang format --- test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp index 8a55ff505..446d80949 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp @@ -170,7 +170,7 @@ class WSLCE2EContainerExecTests auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); - + result = RunWslc(std::format(L"container exec -e {}=A {} env", HostEnvVariableName, WslcContainerName)); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -183,7 +183,7 @@ class WSLCE2EContainerExecTests auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); - + result = RunWslc(std::format(L"container exec -e {} {} env", HostEnvVariableName, WslcContainerName)); result.Verify({.Stderr = L"", .ExitCode = 0}); From 92e00743d83066a2cc0aef9298d28502cd93e487 Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Thu, 9 Apr 2026 00:17:32 -0700 Subject: [PATCH 11/14] Fix tests --- .../wslc/e2e/WSLCE2EContainerAttachTests.cpp | 18 +--- .../wslc/e2e/WSLCE2EContainerCreateTests.cpp | 24 ++--- .../wslc/e2e/WSLCE2EContainerExecTests.cpp | 98 +++++-------------- .../wslc/e2e/WSLCE2EContainerRunTests.cpp | 91 +++++------------ .../wslc/e2e/WSLCE2EContainerTests.cpp | 1 - 5 files changed, 65 insertions(+), 167 deletions(-) diff --git a/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp index 9506d6f20..d155a009c 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp @@ -41,17 +41,14 @@ class WSLCE2EContainerAttachTests return true; } - TEST_METHOD(WSLCE2E_Container_Attach_HelpCommand) + WSLC_TEST_METHOD(WSLCE2E_Container_Attach_HelpCommand) { - WSL2_TEST_ONLY(); - auto result = RunWslc(L"container attach --help"); result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"", .ExitCode = 0}); } - TEST_METHOD(WSLCE2E_Container_Attach_TTY) + WSLC_TEST_METHOD(WSLCE2E_Container_Attach_TTY) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); const auto& prompt = ">"; @@ -85,9 +82,8 @@ class WSLCE2EContainerAttachTests VERIFY_ARE_EQUAL(0, exitCode); } - TEST_METHOD(WSLCE2E_Container_Attach_NoTTY) + WSLC_TEST_METHOD(WSLCE2E_Container_Attach_NoTTY) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); auto result = RunWslc(std::format(L"container run -id --name {} {} cat", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -110,18 +106,14 @@ class WSLCE2EContainerAttachTests session.VerifyNoErrors(); } - TEST_METHOD(WSLCE2E_Container_Attach_MissingContainerId) + WSLC_TEST_METHOD(WSLCE2E_Container_Attach_MissingContainerId) { - WSL2_TEST_ONLY(); - auto result = RunWslc(L"container attach"); result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"Required argument not provided: 'container-id'\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Attach_ContainerNotFound) + WSLC_TEST_METHOD(WSLCE2E_Container_Attach_ContainerNotFound) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container attach {}", WslcContainerName)); result.Verify({.Stderr = L"Element not found. \r\nError code: ERROR_NOT_FOUND\r\n", .ExitCode = 1}); } diff --git a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp index 4af5359e9..bc688e245 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp @@ -357,7 +357,7 @@ class WSLCE2EContainerCreateTests VerifyContainerIsNotListed(WslcContainerName, std::chrono::seconds(2), std::chrono::minutes(1)); } - TEST_METHOD(WSLCE2E_Container_CreateStartAttach_TTY) + WSLC_TEST_METHOD(WSLCE2E_Container_CreateStartAttach_TTY) { VerifyContainerIsNotListed(WslcContainerName); @@ -429,7 +429,7 @@ class WSLCE2EContainerCreateTests result.Verify({.Stdout = L"lifecycle works\n", .Stderr = L"", .ExitCode = ExpectedExitCode}); } - TEST_METHOD(WSLCE2E_Container_Create_UserOption_UidRoot) + WSLC_TEST_METHOD(WSLCE2E_Container_Create_UserOption_UidRoot) { auto result = RunWslc( std::format(L"container create --name {} -u 0 {} sh -c \"id -u; id -g\"", WslcContainerName, DebianImage.NameAndTag())); @@ -460,10 +460,8 @@ class WSLCE2EContainerCreateTests {.Stderr = L"unable to find user user_does_not_exist: no matching entries in passwd file\r\nError code: E_FAIL\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Create_Tmpfs) + WSLC_TEST_METHOD(WSLCE2E_Container_Create_Tmpfs) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format( L"container create --name {} --tmpfs /wslc-tmpfs {} sh -c \"echo -n 'tmpfs_test' > /wslc-tmpfs/data && cat " L"/wslc-tmpfs/data\"", @@ -475,10 +473,8 @@ class WSLCE2EContainerCreateTests result.Verify({.Stdout = L"tmpfs_test", .Stderr = L"", .ExitCode = 0}); } - TEST_METHOD(WSLCE2E_Container_Create_Tmpfs_With_Options) + WSLC_TEST_METHOD(WSLCE2E_Container_Create_Tmpfs_With_Options) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format( L"container create --name {} --tmpfs /wslc-tmpfs:size=64k {} sh -c \"mount | grep -q ' on /wslc-tmpfs type tmpfs ' " L"&& echo mounted\"", @@ -490,10 +486,8 @@ class WSLCE2EContainerCreateTests result.Verify({.Stdout = L"mounted\n", .Stderr = L"", .ExitCode = 0}); } - TEST_METHOD(WSLCE2E_Container_Create_Tmpfs_Multiple_With_Options) + WSLC_TEST_METHOD(WSLCE2E_Container_Create_Tmpfs_Multiple_With_Options) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format( L"container create --name {} --tmpfs /wslc-tmpfs1:size=64k --tmpfs /wslc-tmpfs2:size=128k {} sh -c \"mount | grep -q " L"' on /wslc-tmpfs1 type tmpfs ' && mount | grep -q ' on /wslc-tmpfs2 type tmpfs ' && echo mounted\"", @@ -505,19 +499,15 @@ class WSLCE2EContainerCreateTests result.Verify({.Stdout = L"mounted\n", .Stderr = L"", .ExitCode = 0}); } - TEST_METHOD(WSLCE2E_Container_Create_Tmpfs_RelativePath_Fails) + WSLC_TEST_METHOD(WSLCE2E_Container_Create_Tmpfs_RelativePath_Fails) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container create --name {} --tmpfs wslc-tmpfs {}", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"invalid mount path: 'wslc-tmpfs' mount path must be absolute\r\nError code: E_FAIL\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Create_Tmpfs_EmptyDestination_Fails) + WSLC_TEST_METHOD(WSLCE2E_Container_Create_Tmpfs_EmptyDestination_Fails) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container create --name {} --tmpfs :size=64k {}", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"invalid mount path: '' mount path must be absolute\r\nError code: E_FAIL\r\n", .ExitCode = 1}); diff --git a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp index ab494d495..9a4fcd714 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp @@ -58,24 +58,20 @@ class WSLCE2EContainerExecTests return true; } - TEST_METHOD(WSLCE2E_Container_Exec_HelpCommand) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_HelpCommand) { auto result = RunWslc(L"container exec --help"); result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"", .ExitCode = 0}); } - TEST_METHOD(WSLCE2E_Container_Exec_MissingContainerId) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_MissingContainerId) { - WSL2_TEST_ONLY(); - auto result = RunWslc(L"container exec"); result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"Required argument not provided: 'container-id'\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Exec_MissingCommand) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_MissingCommand) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -83,18 +79,14 @@ class WSLCE2EContainerExecTests result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"Required argument not provided: 'command'\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Exec_ContainerNotFound) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_ContainerNotFound) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container exec {} echo hello", WslcContainerName)); result.Verify({.Stderr = L"Element not found. \r\nError code: ERROR_NOT_FOUND\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Exec_SimpleCommand) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_SimpleCommand) { - WSL2_TEST_ONLY(); - // Run a container in background auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -104,9 +96,8 @@ class WSLCE2EContainerExecTests result.Verify({.Stdout = L"hello\n", .Stderr = L"", .ExitCode = 0}); } - TEST_METHOD(WSLCE2E_Container_Exec_InteractiveTTY) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_InteractiveTTY) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); const auto& prompt = ">"; @@ -137,9 +128,8 @@ class WSLCE2EContainerExecTests VERIFY_ARE_EQUAL(0, exitCode); } - TEST_METHOD(WSLCE2E_Container_Exec_InteractiveNoTTY) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_InteractiveNoTTY) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); auto result = RunWslc(std::format(L"container run -id --name {} {}", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -162,10 +152,8 @@ class WSLCE2EContainerExecTests session.VerifyNoErrors(); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvOption) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvOption) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -175,10 +163,8 @@ class WSLCE2EContainerExecTests VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=A", HostEnvVariableName))); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_KeyOnly_UsesHostValue) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_KeyOnly_UsesHostValue) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -188,10 +174,8 @@ class WSLCE2EContainerExecTests VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvFile) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvFile) { - WSL2_TEST_ONLY(); - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a", "WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); @@ -204,10 +188,8 @@ class WSLCE2EContainerExecTests VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b")); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_MultipleValues) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_MultipleValues) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -219,10 +201,8 @@ class WSLCE2EContainerExecTests VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=value-b", HostEnvVariableName2))); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_KeyOnly_MultipleValues_UsesHostValues) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_KeyOnly_MultipleValues_UsesHostValues) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -233,10 +213,8 @@ class WSLCE2EContainerExecTests VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName2, HostEnvVariableValue2))); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_EmptyValue) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_EmptyValue) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -247,10 +225,8 @@ class WSLCE2EContainerExecTests VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=", HostEnvVariableName))); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_MixedWithEnvFile) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_MixedWithEnvFile) { - WSL2_TEST_ONLY(); - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_MIX_FILE_A=from-file-a", "WSLC_TEST_EXEC_ENV_MIX_FILE_B=from-file-b"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); @@ -265,10 +241,8 @@ class WSLCE2EContainerExecTests VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_MIX_CLI=from-cli")); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_MissingFile) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_MissingFile) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -277,10 +251,8 @@ class WSLCE2EContainerExecTests {.Stderr = L"Environment file 'ENV_FILE_NOT_FOUND' cannot be opened for reading\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_MultipleFiles) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_MultipleFiles) { - WSL2_TEST_ONLY(); - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_FILE_MULTI_A=file1-a", "WSLC_TEST_EXEC_ENV_FILE_MULTI_B=file1-b"}); WriteFile(EnvTestFile2, {"WSLC_TEST_EXEC_ENV_FILE_MULTI_C=file2-c", "WSLC_TEST_EXEC_ENV_FILE_MULTI_D=file2-d"}); @@ -297,10 +269,8 @@ class WSLCE2EContainerExecTests VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_FILE_MULTI_D=file2-d")); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_InvalidContent) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_InvalidContent) { - WSL2_TEST_ONLY(); - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_VALID=ok", "BAD KEY=value"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); @@ -310,10 +280,8 @@ class WSLCE2EContainerExecTests result.Verify({.Stderr = L"Environment variable key 'BAD KEY' cannot contain whitespace\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_DuplicateKeys_Precedence) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_DuplicateKeys_Precedence) { - WSL2_TEST_ONLY(); - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_DUP=from-file-1"}); WriteFile(EnvTestFile2, {"WSLC_TEST_EXEC_ENV_DUP=from-file-2"}); @@ -338,10 +306,8 @@ class WSLCE2EContainerExecTests VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_DUP=from-cli")); } - TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_ValueContainsEquals) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_ValueContainsEquals) { - WSL2_TEST_ONLY(); - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_EQUALS=value=with=equals"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); @@ -353,10 +319,8 @@ class WSLCE2EContainerExecTests VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_EXEC_ENV_EQUALS=value=with=equals")); } - TEST_METHOD(WSLCE2E_Container_Exec_ExitCode_Propagates) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_ExitCode_Propagates) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -364,10 +328,8 @@ class WSLCE2EContainerExecTests result.Verify({.Stdout = L"", .Stderr = L"", .ExitCode = 42}); } - TEST_METHOD(WSLCE2E_Container_Exec_Stderr_Propagates) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_Stderr_Propagates) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -375,10 +337,8 @@ class WSLCE2EContainerExecTests result.Verify({.Stdout = L"", .Stderr = L"exec-error\n", .ExitCode = 0}); } - TEST_METHOD(WSLCE2E_Container_Exec_StoppedContainer) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_StoppedContainer) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run --name {} {} echo hello", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -386,10 +346,8 @@ class WSLCE2EContainerExecTests result.Verify({.Stderr = L"The group or resource is not in the correct state to perform the requested operation. \r\nError code: ERROR_INVALID_STATE\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Exec_UserOption_UidRoot) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_UserOption_UidRoot) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -397,10 +355,8 @@ class WSLCE2EContainerExecTests result.Verify({.Stdout = L"0\n0\n", .Stderr = L"", .ExitCode = 0}); } - TEST_METHOD(WSLCE2E_Container_Exec_UserOption_NameGroupRoot) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_UserOption_NameGroupRoot) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -408,10 +364,8 @@ class WSLCE2EContainerExecTests result.Verify({.Stdout = L"root\n0\n0\n", .Stderr = L"", .ExitCode = 0}); } - TEST_METHOD(WSLCE2E_Container_Exec_UserOption_InvalidGroup_Fails) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_UserOption_InvalidGroup_Fails) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -419,7 +373,7 @@ class WSLCE2EContainerExecTests result.Verify({.Stdout = L"unable to find group badgid: no matching entries in group file\r\n", .ExitCode = 126}); } - TEST_METHOD(WSLCE2E_Container_Exec_WorkDir) + WSLC_TEST_METHOD(WSLCE2E_Container_Exec_WorkDir) { auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); diff --git a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp index 56241aab9..472c4e4b2 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp @@ -113,9 +113,8 @@ class WSLCE2EContainerRunTests VerifyContainerIsListed(WslcContainerName, L"running"); } - TEST_METHOD(WSLCE2E_Container_Run_Remove) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_Remove) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); // Run the container with a valid image @@ -126,9 +125,8 @@ class WSLCE2EContainerRunTests VerifyContainerIsNotListed(WslcContainerName); } - TEST_METHOD(WSLCE2E_Container_Run_EnvOption) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_EnvOption) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); auto result = RunWslc(std::format( @@ -138,9 +136,8 @@ class WSLCE2EContainerRunTests VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=A", HostEnvVariableName))); } - TEST_METHOD(WSLCE2E_Container_Run_EnvOption_MultipleValues) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_EnvOption_MultipleValues) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); auto result = RunWslc(std::format( @@ -155,9 +152,8 @@ class WSLCE2EContainerRunTests VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=B", HostEnvVariableName2))); } - TEST_METHOD(WSLCE2E_Container_Run_EnvOption_KeyOnly_UsesHostValue) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_EnvOption_KeyOnly_UsesHostValue) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); auto result = RunWslc(std::format( @@ -167,9 +163,8 @@ class WSLCE2EContainerRunTests VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName, HostEnvVariableValue))); } - TEST_METHOD(WSLCE2E_Container_Run_EnvOption_KeyOnly_MultipleValues_UsesHostValues) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_EnvOption_KeyOnly_MultipleValues_UsesHostValues) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); auto result = RunWslc(std::format( @@ -184,9 +179,8 @@ class WSLCE2EContainerRunTests VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}={}", HostEnvVariableName2, HostEnvVariableValue2))); } - TEST_METHOD(WSLCE2E_Container_Run_EnvOption_EmptyValue) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_EnvOption_EmptyValue) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); auto result = RunWslc(std::format( @@ -196,9 +190,8 @@ class WSLCE2EContainerRunTests VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"{}=", HostEnvVariableName))); } - TEST_METHOD(WSLCE2E_Container_Run_EnvFile) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_EnvFile) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_FILE_A=env-file-a", "WSLC_TEST_ENV_FILE_B=env-file-b"}); @@ -214,9 +207,8 @@ class WSLCE2EContainerRunTests VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_B=env-file-b")); } - TEST_METHOD(WSLCE2E_Container_Run_EnvOption_MixedWithEnvFile) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_EnvOption_MixedWithEnvFile) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_MIX_FILE_A=from-file-a", "WSLC_TEST_ENV_MIX_FILE_B=from-file-b"}); @@ -233,9 +225,8 @@ class WSLCE2EContainerRunTests VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_MIX_CLI=from-cli")); } - TEST_METHOD(WSLCE2E_Container_Run_EnvFile_MultipleFiles) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_EnvFile_MultipleFiles) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_FILE_MULTI_A=file1-a", "WSLC_TEST_ENV_FILE_MULTI_B=file1-b"}); @@ -256,9 +247,8 @@ class WSLCE2EContainerRunTests VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_FILE_MULTI_D=file2-d")); } - TEST_METHOD(WSLCE2E_Container_Run_EnvFile_MissingFile) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_EnvFile_MissingFile) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); auto result = RunWslc(std::format( @@ -267,9 +257,8 @@ class WSLCE2EContainerRunTests {.Stderr = L"Environment file 'ENV_FILE_NOT_FOUND' cannot be opened for reading\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Run_EnvFile_InvalidContent) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_EnvFile_InvalidContent) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_VALID=ok", "BAD KEY=value"}); @@ -282,9 +271,8 @@ class WSLCE2EContainerRunTests result.Verify({.Stderr = L"Environment variable key 'BAD KEY' cannot contain whitespace\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Run_EnvFile_DuplicateKeys_Precedence) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_EnvFile_DuplicateKeys_Precedence) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_DUP=from-file-1"}); @@ -314,9 +302,8 @@ class WSLCE2EContainerRunTests VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_DUP=from-cli")); } - TEST_METHOD(WSLCE2E_Container_Run_EnvFile_ValueContainsEquals) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_EnvFile_ValueContainsEquals) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_EQUALS=value=with=equals"}); @@ -331,7 +318,7 @@ class WSLCE2EContainerRunTests VERIFY_IS_TRUE(result.StdoutContainsLine(L"WSLC_TEST_ENV_EQUALS=value=with=equals")); } - TEST_METHOD(WSLCE2E_Container_Run_UserOption_NameRoot) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_UserOption_NameRoot) { auto result = RunWslc(std::format(L"container run --rm -u root {} sh -c \"id -un; id -u; id -g\"", DebianImage.NameAndTag())); result.Verify({.Stdout = L"root\n0\n0\n", .Stderr = L"", .ExitCode = 0}); @@ -375,10 +362,8 @@ class WSLCE2EContainerRunTests result.Verify({.Stdout = L"nobody\n65534\n65534\n", .Stderr = L"", .ExitCode = 0}); } - TEST_METHOD(WSLCE2E_Container_Run_PortMultipleMappings) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_PortMultipleMappings) { - WSL2_TEST_ONLY(); - // Start a container with a simple server listening on a port // Map two host ports to the same container port auto result = RunWslc(std::format( @@ -397,13 +382,11 @@ class WSLCE2EContainerRunTests ExpectHttpResponse(std::format(L"http://127.0.0.1:{}", HostTestPort2).c_str(), HTTP_STATUS_OK, true); } - TEST_METHOD(WSLCE2E_Container_Run_PortAlreadyInUse) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_PortAlreadyInUse) { // Bug: https://github.com/microsoft/WSL/issues/14448 SKIP_TEST_NOT_IMPL(); - WSL2_TEST_ONLY(); - // Start a container with a simple server listening on a port auto result1 = RunWslc(std::format( L"container run -d --name {} -p {}:{} {} {}", @@ -420,36 +403,28 @@ class WSLCE2EContainerRunTests } // https://github.com/microsoft/WSL/issues/14433 - TEST_METHOD(WSLCE2E_Container_Run_PortEphemeral_NotSupported) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_PortEphemeral_NotSupported) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -p 80 {}", DebianImage.NameAndTag())); result.Verify({.Stderr = L"Port mappings with ephemeral host ports, specific host IPs, or UDP protocol are not currently supported\r\nError code: ERROR_NOT_SUPPORTED\r\n", .ExitCode = 1}); } // https://github.com/microsoft/WSL/issues/14433 - TEST_METHOD(WSLCE2E_Container_Run_PortUdp_NotSupported) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_PortUdp_NotSupported) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -p 80:80/udp {}", DebianImage.NameAndTag())); result.Verify({.Stderr = L"Port mappings with ephemeral host ports, specific host IPs, or UDP protocol are not currently supported\r\nError code: ERROR_NOT_SUPPORTED\r\n", .ExitCode = 1}); } // https://github.com/microsoft/WSL/issues/14433 - TEST_METHOD(WSLCE2E_Container_Run_PortHostIP_NotSupported) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_PortHostIP_NotSupported) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run -p 127.0.0.1:80:80 {}", DebianImage.NameAndTag())); result.Verify({.Stderr = L"Port mappings with ephemeral host ports, specific host IPs, or UDP protocol are not currently supported\r\nError code: ERROR_NOT_SUPPORTED\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Run_Port_TCP) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_Port_TCP) { - WSL2_TEST_ONLY(); - // Start a container with a simple server listening on a port auto result = RunWslc(std::format( L"container run -d --name {} -p {}:{} {} {}", @@ -474,9 +449,8 @@ class WSLCE2EContainerRunTests VERIFY_ARE_EQUAL("127.0.0.1", portBindings[0].HostIp); } - TEST_METHOD(WSLCE2E_Container_Run_Interactive_TTY) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_Interactive_TTY) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); const auto& prompt = ">"; @@ -501,9 +475,8 @@ class WSLCE2EContainerRunTests VERIFY_ARE_EQUAL(0, exitCode); } - TEST_METHOD(WSLCE2E_Container_Run_Interactive_NoTTY) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_Interactive_NoTTY) { - WSL2_TEST_ONLY(); VerifyContainerIsNotListed(WslcContainerName); auto session = RunWslcInteractive(std::format(L"container run -i --name {} {} cat", WslcContainerName, DebianImage.NameAndTag())); @@ -523,10 +496,8 @@ class WSLCE2EContainerRunTests session.VerifyNoErrors(); } - TEST_METHOD(WSLCE2E_Container_Run_Tmpfs) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_Tmpfs) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format( L"container run --rm --tmpfs /wslc-tmpfs {} sh -c \"echo -n 'tmpfs_test' > /wslc-tmpfs/data && cat " L"/wslc-tmpfs/data\"", @@ -534,10 +505,8 @@ class WSLCE2EContainerRunTests result.Verify({.Stdout = L"tmpfs_test", .Stderr = L"", .ExitCode = 0}); } - TEST_METHOD(WSLCE2E_Container_Run_Tmpfs_With_Options) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_Tmpfs_With_Options) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format( L"container run --rm --tmpfs /wslc-tmpfs:size=64k {} sh -c \"mount | grep -q ' on /wslc-tmpfs type tmpfs ' && echo " L"mounted\"", @@ -545,10 +514,8 @@ class WSLCE2EContainerRunTests result.Verify({.Stdout = L"mounted\n", .Stderr = L"", .ExitCode = 0}); } - TEST_METHOD(WSLCE2E_Container_Run_Tmpfs_Multiple_With_Options) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_Tmpfs_Multiple_With_Options) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format( L"container run --rm --tmpfs /wslc-tmpfs1:size=64k --tmpfs /wslc-tmpfs2:size=128k {} sh -c \"mount | grep -q ' on " L"/wslc-tmpfs1 type tmpfs ' && mount | grep -q ' on /wslc-tmpfs2 type tmpfs ' && echo mounted\"", @@ -556,18 +523,14 @@ class WSLCE2EContainerRunTests result.Verify({.Stdout = L"mounted\n", .Stderr = L"", .ExitCode = 0}); } - TEST_METHOD(WSLCE2E_Container_Run_Tmpfs_RelativePath_Fails) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_Tmpfs_RelativePath_Fails) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run --rm --tmpfs wslc-tmpfs {}", DebianImage.NameAndTag())); result.Verify({.Stderr = L"invalid mount path: 'wslc-tmpfs' mount path must be absolute\r\nError code: E_FAIL\r\n", .ExitCode = 1}); } - TEST_METHOD(WSLCE2E_Container_Run_Tmpfs_EmptyDestination_Fails) + WSLC_TEST_METHOD(WSLCE2E_Container_Run_Tmpfs_EmptyDestination_Fails) { - WSL2_TEST_ONLY(); - auto result = RunWslc(std::format(L"container run --rm --tmpfs :size=64k {}", DebianImage.NameAndTag())); result.Verify({.Stderr = L"invalid mount path: '' mount path must be absolute\r\nError code: E_FAIL\r\n", .ExitCode = 1}); } diff --git a/test/windows/wslc/e2e/WSLCE2EContainerTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerTests.cpp index adf5547da..cd855ba81 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerTests.cpp @@ -36,7 +36,6 @@ class WSLCE2EContainerTests WSLC_TEST_METHOD(WSLCE2E_Container_HelpCommand) { - WSL2_TEST_ONLY(); RunWslc(L"container --help").Verify({.Stdout = GetHelpMessage(), .Stderr = L"", .ExitCode = 0}); } From 02de0b707c3d4389c26bb9437e55fa76f3cf2dd8 Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Thu, 9 Apr 2026 00:23:21 -0700 Subject: [PATCH 12/14] Resolve copilot comment --- .../wslc/e2e/WSLCE2EContainerExecTests.cpp | 16 ++++++++-------- .../wslc/e2e/WSLCE2EContainerRunTests.cpp | 16 ++++++++-------- test/windows/wslc/e2e/WSLCE2EHelpers.cpp | 2 +- test/windows/wslc/e2e/WSLCE2EHelpers.h | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp index 9a4fcd714..f35ca6f40 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp @@ -176,7 +176,7 @@ class WSLCE2EContainerExecTests WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvFile) { - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a", "WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b"}); + WriteTestFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_FILE_A=exec-env-file-a", "WSLC_TEST_EXEC_ENV_FILE_B=exec-env-file-b"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -227,7 +227,7 @@ class WSLCE2EContainerExecTests WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvOption_MixedWithEnvFile) { - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_MIX_FILE_A=from-file-a", "WSLC_TEST_EXEC_ENV_MIX_FILE_B=from-file-b"}); + WriteTestFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_MIX_FILE_A=from-file-a", "WSLC_TEST_EXEC_ENV_MIX_FILE_B=from-file-b"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -253,8 +253,8 @@ class WSLCE2EContainerExecTests WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_MultipleFiles) { - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_FILE_MULTI_A=file1-a", "WSLC_TEST_EXEC_ENV_FILE_MULTI_B=file1-b"}); - WriteFile(EnvTestFile2, {"WSLC_TEST_EXEC_ENV_FILE_MULTI_C=file2-c", "WSLC_TEST_EXEC_ENV_FILE_MULTI_D=file2-d"}); + WriteTestFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_FILE_MULTI_A=file1-a", "WSLC_TEST_EXEC_ENV_FILE_MULTI_B=file1-b"}); + WriteTestFile(EnvTestFile2, {"WSLC_TEST_EXEC_ENV_FILE_MULTI_C=file2-c", "WSLC_TEST_EXEC_ENV_FILE_MULTI_D=file2-d"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -271,7 +271,7 @@ class WSLCE2EContainerExecTests WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_InvalidContent) { - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_VALID=ok", "BAD KEY=value"}); + WriteTestFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_VALID=ok", "BAD KEY=value"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -282,8 +282,8 @@ class WSLCE2EContainerExecTests WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_DuplicateKeys_Precedence) { - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_DUP=from-file-1"}); - WriteFile(EnvTestFile2, {"WSLC_TEST_EXEC_ENV_DUP=from-file-2"}); + WriteTestFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_DUP=from-file-1"}); + WriteTestFile(EnvTestFile2, {"WSLC_TEST_EXEC_ENV_DUP=from-file-2"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); @@ -308,7 +308,7 @@ class WSLCE2EContainerExecTests WSLC_TEST_METHOD(WSLCE2E_Container_Exec_EnvFile_ValueContainsEquals) { - WriteFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_EQUALS=value=with=equals"}); + WriteTestFile(EnvTestFile1, {"WSLC_TEST_EXEC_ENV_EQUALS=value=with=equals"}); auto result = RunWslc(std::format(L"container run -d --name {} {} sleep infinity", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); diff --git a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp index 472c4e4b2..831854110 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp @@ -194,7 +194,7 @@ class WSLCE2EContainerRunTests { VerifyContainerIsNotListed(WslcContainerName); - WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_FILE_A=env-file-a", "WSLC_TEST_ENV_FILE_B=env-file-b"}); + WriteTestFile(EnvTestFile1, {"WSLC_TEST_ENV_FILE_A=env-file-a", "WSLC_TEST_ENV_FILE_B=env-file-b"}); auto result = RunWslc(std::format( L"container run --rm --name {} --env-file {} {} env", @@ -211,7 +211,7 @@ class WSLCE2EContainerRunTests { VerifyContainerIsNotListed(WslcContainerName); - WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_MIX_FILE_A=from-file-a", "WSLC_TEST_ENV_MIX_FILE_B=from-file-b"}); + WriteTestFile(EnvTestFile1, {"WSLC_TEST_ENV_MIX_FILE_A=from-file-a", "WSLC_TEST_ENV_MIX_FILE_B=from-file-b"}); auto result = RunWslc(std::format( L"container run --rm --name {} -e WSLC_TEST_ENV_MIX_CLI=from-cli --env-file {} {} env", @@ -229,9 +229,9 @@ class WSLCE2EContainerRunTests { VerifyContainerIsNotListed(WslcContainerName); - WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_FILE_MULTI_A=file1-a", "WSLC_TEST_ENV_FILE_MULTI_B=file1-b"}); + WriteTestFile(EnvTestFile1, {"WSLC_TEST_ENV_FILE_MULTI_A=file1-a", "WSLC_TEST_ENV_FILE_MULTI_B=file1-b"}); - WriteFile(EnvTestFile2, {"WSLC_TEST_ENV_FILE_MULTI_C=file2-c", "WSLC_TEST_ENV_FILE_MULTI_D=file2-d"}); + WriteTestFile(EnvTestFile2, {"WSLC_TEST_ENV_FILE_MULTI_C=file2-c", "WSLC_TEST_ENV_FILE_MULTI_D=file2-d"}); auto result = RunWslc(std::format( L"container run --rm --name {} --env-file {} --env-file {} {} env", @@ -261,7 +261,7 @@ class WSLCE2EContainerRunTests { VerifyContainerIsNotListed(WslcContainerName); - WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_VALID=ok", "BAD KEY=value"}); + WriteTestFile(EnvTestFile1, {"WSLC_TEST_ENV_VALID=ok", "BAD KEY=value"}); auto result = RunWslc(std::format( L"container run --rm --name {} --env-file {} {} env", @@ -275,9 +275,9 @@ class WSLCE2EContainerRunTests { VerifyContainerIsNotListed(WslcContainerName); - WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_DUP=from-file-1"}); + WriteTestFile(EnvTestFile1, {"WSLC_TEST_ENV_DUP=from-file-1"}); - WriteFile(EnvTestFile2, {"WSLC_TEST_ENV_DUP=from-file-2"}); + WriteTestFile(EnvTestFile2, {"WSLC_TEST_ENV_DUP=from-file-2"}); // Later --env-file should win over earlier --env-file for duplicate keys auto result = RunWslc(std::format( @@ -306,7 +306,7 @@ class WSLCE2EContainerRunTests { VerifyContainerIsNotListed(WslcContainerName); - WriteFile(EnvTestFile1, {"WSLC_TEST_ENV_EQUALS=value=with=equals"}); + WriteTestFile(EnvTestFile1, {"WSLC_TEST_ENV_EQUALS=value=with=equals"}); auto result = RunWslc(std::format( L"container run --rm --name {} --env-file {} {} env", diff --git a/test/windows/wslc/e2e/WSLCE2EHelpers.cpp b/test/windows/wslc/e2e/WSLCE2EHelpers.cpp index 8e4f7a3c9..7f8a2667b 100644 --- a/test/windows/wslc/e2e/WSLCE2EHelpers.cpp +++ b/test/windows/wslc/e2e/WSLCE2EHelpers.cpp @@ -342,7 +342,7 @@ void EnsureSessionIsTerminated(const std::wstring& sessionName) } } -void WriteFile(const std::filesystem::path& filePath, const std::vector& lines) +void WriteTestFile(const std::filesystem::path& filePath, const std::vector& lines) { std::ofstream file(filePath, std::ios::out | std::ios::trunc | std::ios::binary); VERIFY_IS_TRUE(file.is_open()); diff --git a/test/windows/wslc/e2e/WSLCE2EHelpers.h b/test/windows/wslc/e2e/WSLCE2EHelpers.h index 60476c180..ffdf30e16 100644 --- a/test/windows/wslc/e2e/WSLCE2EHelpers.h +++ b/test/windows/wslc/e2e/WSLCE2EHelpers.h @@ -131,7 +131,7 @@ void EnsureImageIsDeleted(const TestImage& image); void EnsureImageContainersAreDeleted(const TestImage& image); void EnsureSessionIsTerminated(const std::wstring& sessionName = L""); -void WriteFile(const std::filesystem::path& filePath, const std::vector& envVariableLines); +void WriteTestFile(const std::filesystem::path& filePath, const std::vector& envVariableLines); std::wstring GetPythonHttpServerScript(uint16_t port); // Default timeout of 0 will execute once. From 4a35c4aa0a9f998a7751a4be4ece7d285ddf3bb4 Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Fri, 10 Apr 2026 16:39:03 -0700 Subject: [PATCH 13/14] Fix test --- test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp index f35ca6f40..116f02b1c 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp @@ -342,8 +342,10 @@ class WSLCE2EContainerExecTests auto result = RunWslc(std::format(L"container run --name {} {} echo hello", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); + auto inspect = InspectContainer(WslcContainerName); result = RunWslc(std::format(L"container exec {} echo should-fail", WslcContainerName)); - result.Verify({.Stderr = L"The group or resource is not in the correct state to perform the requested operation. \r\nError code: ERROR_INVALID_STATE\r\n", .ExitCode = 1}); + auto errorMessage = std::format(L"Container '{}' is not running.\r\nError code: WSLC_E_CONTAINER_NOT_RUNNING\r\n", inspect.Id); + result.Verify({.Stderr = errorMessage, .ExitCode = 1}); } WSLC_TEST_METHOD(WSLCE2E_Container_Exec_UserOption_UidRoot) From 8e21a68b203dc4c47213bfb94727c6df440cb058 Mon Sep 17 00:00:00 2001 From: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Date: Mon, 13 Apr 2026 10:51:57 -0700 Subject: [PATCH 14/14] Fix sdk tests --- test/windows/WslcSdkTests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/windows/WslcSdkTests.cpp b/test/windows/WslcSdkTests.cpp index 1d041c9a4..3ad22a2e9 100644 --- a/test/windows/WslcSdkTests.cpp +++ b/test/windows/WslcSdkTests.cpp @@ -2048,7 +2048,7 @@ class WslcSdkTests VERIFY_SUCCEEDED(WslcSetProcessSettingsCmdLine(&execSettings, execArgv, ARRAYSIZE(execArgv))); UniqueProcess execProcess; - VERIFY_ARE_EQUAL(WslcCreateContainerProcess(container.get(), &execSettings, &execProcess, nullptr), static_cast(0x8007139f)); // ERROR_CONTAINER_STOPPED + VERIFY_ARE_EQUAL(WslcCreateContainerProcess(container.get(), &execSettings, &execProcess, nullptr), static_cast(WSLC_E_CONTAINER_NOT_RUNNING)); } WSLC_TEST_METHOD(DuplicateContainerName) @@ -2088,7 +2088,7 @@ class WslcSdkTests VERIFY_SUCCEEDED(WslcStartContainer(container.get(), WSLC_CONTAINER_START_FLAG_NONE, nullptr)); // Deleting a running container without force flag should fail - VERIFY_ARE_EQUAL(WslcDeleteContainer(container.get(), WSLC_DELETE_CONTAINER_FLAG_NONE, nullptr), static_cast(0x8007139f)); // ERROR_CONTAINER_STOPPED + VERIFY_ARE_EQUAL(WslcDeleteContainer(container.get(), WSLC_DELETE_CONTAINER_FLAG_NONE, nullptr), static_cast(WSLC_E_CONTAINER_IS_RUNNING)); } WSLC_TEST_METHOD(DeleteNonExistentImage)