Add github issue suggestion in user visible error (#41432)

This PR adds a "search or file issue on github" suggestion in all user visible errors to: Help users find solutions faster. Collect more user reported issues to help reliability improvements. This PR also updates all tests checking the error message to use a unified function for creating the expected error message.

Feng Wang committed Aug 26, 2026 at 11:05 UTC 00df65ad829adcdcbe0cb82af5179f67f6234464
27 files changed +368 -273
localization/strings/en-US/Resources.resw
+3 -2
@@ -1169,8 +1169,9 @@ This prompt will time out in 60 seconds.</value>
1169 </data>
1170 <data name="MessageErrorCode" xml:space="preserve">
1171 <value>{}
1172 -Error code: {}</value>
1173 - <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
1172 +Error code: {}
1173 +If this error was unexpected, please consider searching for existing issues or filing a new issue at https://github.com/microsoft/WSL/issues.</value>
1174 + <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated{Locked="https://github.com/microsoft/WSL/issues"}</comment>
1175 </data>
1176 <data name="MessageInvalidJson" xml:space="preserve">
1177 <value>Invalid JSON document. Parse error: {}</value>
test/windows/Common.cpp
+10
@@ -3149,3 +3149,13 @@ void ValidateCOMErrorMessageContains(const std::wstring& ExpectedSubstring)
3149 VERIFY_FAIL();
3150 }
3151 }
3152 +
3153 +std::wstring FormatErrorMessage(std::wstring_view message, std::wstring_view errorCode)
3154 +{
3155 + return std::format(
3156 + L"{}\r\nError code: {}\r\n"
3157 + L"If this error was unexpected, please consider searching for existing issues or filing a new issue at "
3158 + L"https://github.com/microsoft/WSL/issues.\r\n",
3159 + message,
3160 + errorCode);
3161 +}
test/windows/Common.h
+2
@@ -723,3 +723,5 @@ void WriteSocket(SOCKET Socket, const void* data, size_t size);
723 void ValidateCOMErrorMessage(const std::optional<std::wstring>& Expected, const std::source_location& Source = std::source_location::current());
724
725 void ValidateCOMErrorMessageContains(const std::wstring& ExpectedSubstring);
726 +
727 +std::wstring FormatErrorMessage(std::wstring_view message, std::wstring_view errorCode);
test/windows/InstallerTests.cpp
+4 -4
@@ -721,10 +721,10 @@ class InstallerTests
721 // Validate that calling wsl.exe triggers the install.
722 auto [output, warnings] = LxsstuLaunchWslAndCaptureOutput(L"echo ok", -1, nulDevice.get());
723 VERIFY_ARE_EQUAL(
724 - L"\r\nAnother application has exclusive access to the file 'C:\\Program Files\\WSL\\wsl.exe'. Please shut down all "
725 - L"other applications, then click Retry.\r\n"
726 - L"Update failed (exit code: 1603).\r\n"
727 - L"Error code: Wsl/CallMsi/Install/ERROR_INSTALL_FAILURE\r\n",
724 + FormatErrorMessage(
725 + L"\r\nAnother application has exclusive access to the file 'C:\\Program Files\\WSL\\wsl.exe'. Please shut "
726 + L"down all other applications, then click Retry.\r\nUpdate failed (exit code: 1603).",
727 + L"Wsl/CallMsi/Install/ERROR_INSTALL_FAILURE"),
728 output);
729 }
730
test/windows/MountTests.cpp
+3 -2
@@ -353,8 +353,9 @@ class MountTests
353 const auto [output, error] = LxsstuLaunchWslAndCaptureOutput(mountCommand, -1);
354 VERIFY_ARE_EQUAL(
355 output,
356 - L"The mount name cannot be empty, '.', '..', or contain '/'. Please retry with a valid mount name.\r\n"
357 - L"Error code: Wsl/Service/MountDisk/WSL_E_VM_MODE_INVALID_MOUNT_NAME\r\n",
356 + FormatErrorMessage(
357 + L"The mount name cannot be empty, '.', '..', or contain '/'. Please retry with a valid mount name.",
358 + L"Wsl/Service/MountDisk/WSL_E_VM_MODE_INVALID_MOUNT_NAME"),
359 name);
360 VERIFY_ARE_EQUAL(error, L"", name);
361 }
test/windows/PluginTests.cpp
+31 -26
@@ -109,7 +109,7 @@ class PluginTests
109 RestartWslService();
110 }
111
112 - static void StartWsl(int expectedExitCode, LPCWSTR ExpectedOutput = nullptr)
112 + static void StartWsl(int expectedExitCode, const std::wstring& expectedOutput = {})
113 {
114 auto [output, error] = LxsstuLaunchWslAndCaptureOutput(L"echo -n OK", expectedExitCode);
115 if (expectedExitCode == 0)
@@ -118,7 +118,7 @@ class PluginTests
118 }
119 else
120 {
121 - VERIFY_ARE_EQUAL(output, ExpectedOutput);
121 + VERIFY_ARE_EQUAL(output, expectedOutput);
122 }
123 }
124
@@ -299,8 +299,9 @@ class PluginTests
299 ConfigurePlugin(PluginTestType::Success);
300 StartWsl(
301 -1,
302 - L"A fatal error was returned by plugin 'TestPlugin'\r\nError code: "
303 - L"Wsl/Service/CreateInstance/CreateVm/Plugin/E_ACCESSDENIED\r\n");
302 + FormatErrorMessage(
303 + L"A fatal error was returned by plugin 'TestPlugin'",
304 + L"Wsl/Service/CreateInstance/CreateVm/Plugin/E_ACCESSDENIED"));
305
306 ValidateLogFile(ExpectedOutput);
307 }
@@ -374,8 +375,9 @@ class PluginTests
375 ConfigurePlugin(PluginTestType::PluginRequiresUpdate);
376 StartWsl(
377 -1,
377 - L"The plugin 'TestPlugin' requires a newer version of WSL. Please run: wsl.exe --update\r\nError code: "
378 - L"Wsl/Service/CreateInstance/CreateVm/Plugin/WSL_E_PLUGIN_REQUIRES_UPDATE\r\n");
378 + FormatErrorMessage(
379 + L"The plugin 'TestPlugin' requires a newer version of WSL. Please run: wsl.exe --update",
380 + L"Wsl/Service/CreateInstance/CreateVm/Plugin/WSL_E_PLUGIN_REQUIRES_UPDATE"));
381
382 ValidateLogFile(ExpectedOutput);
383 }
@@ -413,8 +415,8 @@ class PluginTests
415 ConfigurePlugin(PluginTestType::FailToLoad);
416 StartWsl(
417 -1,
416 - L"A fatal error was returned by plugin 'TestPlugin'\r\nError code: "
417 - L"Wsl/Service/CreateInstance/CreateVm/Plugin/E_UNEXPECTED\r\n");
418 + FormatErrorMessage(
419 + L"A fatal error was returned by plugin 'TestPlugin'", L"Wsl/Service/CreateInstance/CreateVm/Plugin/E_UNEXPECTED"));
420 ValidateLogFile(ExpectedOutput);
421 }
422
@@ -440,8 +442,8 @@ class PluginTests
442 ConfigurePlugin(PluginTestType::FailToStartVm);
443 StartWsl(
444 -1,
443 - L"A fatal error was returned by plugin 'TestPlugin'\r\nError code: "
444 - L"Wsl/Service/CreateInstance/CreateVm/Plugin/E_UNEXPECTED\r\n");
445 + FormatErrorMessage(
446 + L"A fatal error was returned by plugin 'TestPlugin'", L"Wsl/Service/CreateInstance/CreateVm/Plugin/E_UNEXPECTED"));
447 ValidateLogFile(ExpectedOutput);
448 }
449
@@ -460,13 +462,15 @@ class PluginTests
462
463 StartWsl(
464 -1,
463 - L"A fatal error was returned by plugin 'TestPlugin'. Error message: 'Plugin error message'\r\nError code: "
464 - L"Wsl/Service/CreateInstance/CreateVm/Plugin/E_UNEXPECTED\r\n");
465 + FormatErrorMessage(
466 + L"A fatal error was returned by plugin 'TestPlugin'. Error message: 'Plugin error message'",
467 + L"Wsl/Service/CreateInstance/CreateVm/Plugin/E_UNEXPECTED"));
468
469 StartWsl(
470 -1,
468 - L"A fatal error was returned by plugin 'TestPlugin'. Error message: 'Plugin error message'\r\nError code: "
469 - L"Wsl/Service/CreateInstance/CreateVm/Plugin/E_UNEXPECTED\r\n");
471 + FormatErrorMessage(
472 + L"A fatal error was returned by plugin 'TestPlugin'. Error message: 'Plugin error message'",
473 + L"Wsl/Service/CreateInstance/CreateVm/Plugin/E_UNEXPECTED"));
474
475 ValidateLogFile(ExpectedOutput);
476 }
@@ -495,12 +499,11 @@ class PluginTests
499 OnDistroStarted: E_UNEXPECTED
500 VM Stopping)";
501
498 - constexpr auto ExpectedError =
499 - L"A fatal error was returned by plugin 'TestPlugin'\r\nError code: "
500 - L"Wsl/Service/CreateInstance/Plugin/E_UNEXPECTED\r\n";
501 -
502 ConfigurePlugin(PluginTestType::FailToStartDistro);
503 - StartWsl(-1, ExpectedError);
503 + StartWsl(
504 + -1,
505 + FormatErrorMessage(
506 + L"A fatal error was returned by plugin 'TestPlugin'", L"Wsl/Service/CreateInstance/Plugin/E_UNEXPECTED"));
507 ValidateLogFile(ExpectedOutput);
508 }
509
@@ -530,8 +533,9 @@ class PluginTests
533 ConfigurePlugin(PluginTestType::ErrorMessageStartVm);
534 StartWsl(
535 -1,
533 - L"A fatal error was returned by plugin 'TestPlugin'. Error message: 'StartVm plugin error message'\r\nError code: "
534 - L"Wsl/Service/CreateInstance/CreateVm/Plugin/E_FAIL\r\n");
536 + FormatErrorMessage(
537 + L"A fatal error was returned by plugin 'TestPlugin'. Error message: 'StartVm plugin error message'",
538 + L"Wsl/Service/CreateInstance/CreateVm/Plugin/E_FAIL"));
539
540 ValidateLogFile(ExpectedOutput);
541 }
@@ -548,9 +552,9 @@ class PluginTests
552 ConfigurePlugin(PluginTestType::ErrorMessageStartDistro);
553 StartWsl(
554 -1,
551 - L"A fatal error was returned by plugin 'TestPlugin'. Error message: 'StartDistro plugin error message'\r\nError "
552 - L"code: "
553 - L"Wsl/Service/CreateInstance/Plugin/E_FAIL\r\n");
555 + FormatErrorMessage(
556 + L"A fatal error was returned by plugin 'TestPlugin'. Error message: 'StartDistro plugin error message'",
557 + L"Wsl/Service/CreateInstance/Plugin/E_FAIL"));
558
559 ValidateLogFile(ExpectedOutput);
560 }
@@ -1006,7 +1010,8 @@ class PluginTests
1010 ConfigurePlugin(PluginTestType::ErrorMessageStartDistro);
1011 StartWsl(
1012 -1,
1009 - L"A fatal error was returned by plugin 'TestPlugin'\r\nError code: "
1010 - L"Wsl/Service/CreateInstance/CreateVm/Plugin/TRUST_E_NOSIGNATURE\r\n");
1013 + FormatErrorMessage(
1014 + L"A fatal error was returned by plugin 'TestPlugin'",
1015 + L"Wsl/Service/CreateInstance/CreateVm/Plugin/TRUST_E_NOSIGNATURE"));
1016 }
1017 };
test/windows/PolicyTests.cpp
+23 -19
@@ -110,8 +110,9 @@ class PolicyTest
110 auto revert = SetPolicy(c_allowDiskMount, 1);
111 ValidateOutput(
112 L"--mount DoesNotExist",
113 - L"Failed to attach disk 'DoesNotExist' to WSL2: The system cannot find the file specified. \r\n"
114 - L"Error code: Wsl/Service/AttachDisk/MountDisk/HCS/ERROR_FILE_NOT_FOUND\r\n");
113 + FormatErrorMessage(
114 + L"Failed to attach disk 'DoesNotExist' to WSL2: The system cannot find the file specified. ",
115 + L"Wsl/Service/AttachDisk/MountDisk/HCS/ERROR_FILE_NOT_FOUND"));
116 }
117
118 WSL2_TEST_METHOD(MountPolicyDisabled)
@@ -120,7 +121,7 @@ class PolicyTest
121 auto revert = SetPolicy(c_allowDiskMount, 0);
122 ValidateOutput(
123 L"--mount DoesNotExist",
123 - L"wsl.exe --mount is disabled by the computer policy.\r\nError code: Wsl/Service/WSL_E_DISK_MOUNT_DISABLED\r\n");
124 + FormatErrorMessage(L"wsl.exe --mount is disabled by the computer policy.", L"Wsl/Service/WSL_E_DISK_MOUNT_DISABLED"));
125 }
126
127 void ValidatePolicy(LPCWSTR Name, LPCWSTR Config, LPCWSTR ExpectedWarnings, const std::function<void(DWORD)>& Validate = [](auto) {})
@@ -210,9 +211,9 @@ class PolicyTest
211
212 ValidateOutput(
213 L"echo ok",
213 - std::format(
214 - L"{}\r\nError code: Wsl/Service/CreateInstance/CreateVm/WSL_E_CUSTOM_KERNEL_NOT_FOUND\r\n",
215 - wsl::shared::Localization::MessageCustomKernelNotFound(wslConfigPath, nonExistentFile)));
214 + FormatErrorMessage(
215 + wsl::shared::Localization::MessageCustomKernelNotFound(wslConfigPath, nonExistentFile),
216 + L"Wsl/Service/CreateInstance/CreateVm/WSL_E_CUSTOM_KERNEL_NOT_FOUND"));
217 }
218
219 // Disable the custom kernel policy and validate that the expected warnings are shown.
@@ -246,9 +247,9 @@ class PolicyTest
247
248 ValidateOutput(
249 L"echo ok",
249 - L"The custom system distribution specified in " + wslConfigPath +
250 - L" was not found or is not the correct format.\r\nError code: "
251 - L"Wsl/Service/CreateInstance/CreateVm/WSL_E_CUSTOM_SYSTEM_DISTRO_ERROR\r\n");
250 + FormatErrorMessage(
251 + L"The custom system distribution specified in " + wslConfigPath + L" was not found or is not the correct format.",
252 + L"Wsl/Service/CreateInstance/CreateVm/WSL_E_CUSTOM_SYSTEM_DISTRO_ERROR"));
253 }
254
255 {
@@ -321,13 +322,16 @@ class PolicyTest
322 {
323 ValidateOutput(
324 L"--set-version " LXSS_DISTRO_NAME_TEST_L L" 1",
324 - L"WSL1 is disabled by the computer policy.\r\nError code: Wsl/Service/WSL_E_WSL1_DISABLED\r\n");
325 + FormatErrorMessage(L"WSL1 is disabled by the computer policy.", L"Wsl/Service/WSL_E_WSL1_DISABLED"));
326 }
327 else
328 {
329 ValidateOutput(
329 - L"echo ok",
330 - L"WSL1 is disabled by the computer policy.\r\nPlease run 'wsl.exe --set-version " LXSS_DISTRO_NAME_TEST_L L" 2' to upgrade to WSL2.\r\nError code: Wsl/Service/CreateInstance/WSL_E_WSL1_DISABLED\r\n");
330 + L"echo ok",
331 + FormatErrorMessage(
332 + L"WSL1 is disabled by the computer policy.\r\nPlease run 'wsl.exe "
333 + L"--set-version " LXSS_DISTRO_NAME_TEST_L L" 2' to upgrade to WSL2.",
334 + L"Wsl/Service/CreateInstance/WSL_E_WSL1_DISABLED"));
335 }
336 }
337 }
@@ -361,9 +365,9 @@ class PolicyTest
365 auto [output, _] = LxsstuLaunchWslAndCaptureOutput(L"/bin/true", -1);
366 VERIFY_ARE_EQUAL(
367 output,
364 - L"This program is blocked by group policy. For more information, contact your system administrator. "
365 - L"\r\nError "
366 - L"code: Wsl/ERROR_ACCESS_DISABLED_BY_POLICY\r\n");
368 + FormatErrorMessage(
369 + L"This program is blocked by group policy. For more information, contact your system administrator. ",
370 + L"Wsl/ERROR_ACCESS_DISABLED_BY_POLICY"));
371 }
372 };
373
@@ -456,10 +460,10 @@ class PolicyTest
460 // The disabled message must go to stderr only -- never to stdout.
461 VERIFY_ARE_EQUAL(L"", stdoutText);
462
459 - // The wslc CLI renders failures via MessageErrorCode("{}\nError code: {}") and
463 + // The wslc CLI renders failures via MessageErrorCode and
464 // PrintMessage adds a trailing newline; line endings are \r\n through console pipes.
465 const auto expected =
462 - wsl::shared::Localization::MessageWSLContainerDisabled() + L"\r\nError code: WSLC_E_CONTAINER_DISABLED\r\n";
466 + FormatErrorMessage(wsl::shared::Localization::MessageWSLContainerDisabled(), L"WSLC_E_CONTAINER_DISABLED");
467 VERIFY_ARE_EQUAL(expected, stderrText);
468 }
469
@@ -476,8 +480,8 @@ class PolicyTest
480 VERIFY_ARE_NOT_EQUAL(0, exitCode);
481 VERIFY_ARE_EQUAL(L"", stdoutText);
482
479 - const auto expected = wsl::shared::Localization::MessageRegistryBlockedByPolicy(L"docker.io") +
480 - L"\r\nError code: WSLC_E_REGISTRY_BLOCKED_BY_POLICY\r\n";
483 + const auto expected = FormatErrorMessage(
484 + wsl::shared::Localization::MessageRegistryBlockedByPolicy(L"docker.io"), L"WSLC_E_REGISTRY_BLOCKED_BY_POLICY");
485 VERIFY_ARE_EQUAL(expected, stderrText);
486 }
487
test/windows/SimpleTests.cpp
+5 -3
@@ -119,9 +119,11 @@ class SimpleTests
119 // Setting a distro VHD to sparse requires the allow unsafe flag.
120 ValidateOutput(
121 std::format(L"{} {} {} {}", WSL_MANAGE_ARG, tempDistro, WSL_MANAGE_ARG_SET_SPARSE_OPTION_LONG, L"true").c_str(),
122 - L"Sparse VHD support is currently disabled due to potential data corruption.\r\n"
123 - L"To force a distribution to use a sparse VHD, please run:\r\n"
124 - L"wsl.exe --manage <DistributionName> --set-sparse true --allow-unsafe\r\nError code: Wsl/Service/E_INVALIDARG\r\n",
122 + FormatErrorMessage(
123 + L"Sparse VHD support is currently disabled due to potential data corruption.\r\n"
124 + L"To force a distribution to use a sparse VHD, please run:\r\n"
125 + L"wsl.exe --manage <DistributionName> --set-sparse true --allow-unsafe",
126 + L"Wsl/Service/E_INVALIDARG"),
127 L"",
128 -1);
129
test/windows/UnitTests.cpp
+140 -124
@@ -166,7 +166,8 @@ class UnitTests
166 auto [out, err] =
167 LxsstuLaunchWslAndCaptureOutput(std::format(L"--export {} {} --format vhd", LXSS_DISTRO_NAME_TEST_L, vhdPath), -1);
168
169 - VERIFY_ARE_EQUAL(out, L"This operation is only supported by WSL2.\r\nError code: Wsl/Service/WSL_E_WSL2_NEEDED\r\n");
169 + VERIFY_ARE_EQUAL(
170 + out, FormatErrorMessage(L"This operation is only supported by WSL2.", L"Wsl/Service/WSL_E_WSL2_NEEDED"));
171 VERIFY_ARE_EQUAL(err, L"");
172 }
173
@@ -1195,17 +1196,14 @@ class UnitTests
1196 {
1197 validateOutput(
1198 commandLine.c_str(),
1198 - std::format(
1199 - L"Failed to create disk '{}ext4.vhdx': The file exists. \r\n"
1200 - L"Error code: Wsl/Service/RegisterDistro/ERROR_FILE_EXISTS\r\n",
1201 - LXSST_IMPORT_DISTRO_TEST_DIR));
1199 + FormatErrorMessage(
1200 + std::format(L"Failed to create disk '{}ext4.vhdx': The file exists. ", LXSST_IMPORT_DISTRO_TEST_DIR),
1201 + L"Wsl/Service/RegisterDistro/ERROR_FILE_EXISTS"));
1202 }
1203 else
1204 {
1205 validateOutput(
1206 - commandLine.c_str(),
1207 - L"The file exists. \r\n"
1208 - L"Error code: Wsl/Service/RegisterDistro/ERROR_FILE_EXISTS\r\n");
1206 + commandLine.c_str(), FormatErrorMessage(L"The file exists. ", L"Wsl/Service/RegisterDistro/ERROR_FILE_EXISTS"));
1207 }
1208
1209 commandLine = std::format(L"--import dummy {} {} --version {}", LXSST_IMPORT_DISTRO_TEST_DIR, vhdFileName, version);
@@ -1216,8 +1214,7 @@ class UnitTests
1214 commandLine = std::format(L"--import dummy {} {} --vhd --version 1", LXSST_IMPORT_DISTRO_TEST_DIR, vhdFileName);
1215 validateOutput(
1216 commandLine.c_str(),
1219 - L"This operation is only supported by WSL2.\r\n"
1220 - L"Error code: Wsl/Service/RegisterDistro/WSL_E_WSL2_NEEDED\r\n");
1217 + FormatErrorMessage(L"This operation is only supported by WSL2.", L"Wsl/Service/RegisterDistro/WSL_E_WSL2_NEEDED"));
1218 }
1219
1220 //
@@ -1235,8 +1232,8 @@ class UnitTests
1232 commandLine = std::format(L"--import path-conflict-distro \"{}\" \"{}\" --version {}", basePath, tarFileName, version);
1233 validateOutput(
1234 commandLine.c_str(),
1238 - L"The supplied install location is already in use.\r\n"
1239 - L"Error code: Wsl/Service/RegisterDistro/ERROR_FILE_EXISTS\r\n");
1235 + FormatErrorMessage(
1236 + L"The supplied install location is already in use.", L"Wsl/Service/RegisterDistro/ERROR_FILE_EXISTS"));
1237 }
1238
1239 //
@@ -1277,7 +1274,7 @@ class UnitTests
1274 auto [out, err] = LxsstuLaunchWslAndCaptureOutput(commandLine.c_str(), -1);
1275
1276 VERIFY_ARE_EQUAL(
1280 - out, L"Importing the distribution failed.\r\nError code: Wsl/Service/RegisterDistro/WSL_E_IMPORT_FAILED\r\n");
1277 + out, FormatErrorMessage(L"Importing the distribution failed.", L"Wsl/Service/RegisterDistro/WSL_E_IMPORT_FAILED"));
1278 VERIFY_ARE_EQUAL(err, L"bsdtar: Error opening archive: Unrecognized archive format\n");
1279 }
1280
@@ -1422,7 +1419,7 @@ class UnitTests
1419 auto [output, _] = LxsstuLaunchWslAndCaptureOutput(
1420 Cmd.c_str(), wcscmp(EntryPoint, L"bash.exe") == 0 ? 1 : -1, nullptr, nullptr, EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, EntryPoint);
1421
1425 - const auto expectedOutput = Message + L"\r\nError code: " + Code + L"\r\n";
1422 + const auto expectedOutput = FormatErrorMessage(Message, Code);
1423
1424 if (!wsl::shared::string::IsEqual(output, expectedOutput, ignoreCasing))
1425 {
@@ -1519,9 +1516,7 @@ class UnitTests
1516 L"-d DummyBrokenDistro",
1517 L"An error occurred accessing the registry. Path: '\\REGISTRY\\USER\\" + Sid +
1518 L"\\Software\\Microsoft\\Windows\\CurrentVersion\\Lxss\\{baa405ef-1822-4bbe-84e2-30e4c6330d42}"
1522 - L"\\Version'."
1523 - L" "
1524 - L"Error: Data of this type is not supported. ",
1519 + L"\\Version'. Error: Data of this type is not supported. ",
1520 L"Wsl/Service/ReadDistroConfig/ERROR_UNSUPPORTED_TYPE",
1521 {},
1522 L"wsl.exe",
@@ -1932,12 +1927,6 @@ Usage:
1927 Unregisters the distribution and deletes the root filesystem.
1928 )""";
1929
1935 - const std::wstring WslInstallHelpMessage =
1936 - LR"""(Invalid distribution name: 'foo'.
1937 -To get a list of valid distributions, use 'wsl.exe --list --online'.
1938 -Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
1939 -)""";
1940 -
1930 auto AddCrlf = [](const std::wstring& Input) {
1931 std::wstring MessageWithCrlf;
1932
@@ -1963,7 +1952,12 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
1952 RegistryKeyChange<std::wstring> keyChange(
1953 HKEY_LOCAL_MACHINE, LXSS_REGISTRY_PATH, wsl::windows::common::distribution::c_distroUrlRegistryValue, c_testDistributionEndpoint);
1954
1966 - VerifyOutput(L"--install foo", AddCrlf(WslInstallHelpMessage), -1);
1955 + VerifyOutput(
1956 + L"--install foo",
1957 + FormatErrorMessage(
1958 + L"Invalid distribution name: 'foo'.\r\nTo get a list of valid distributions, use 'wsl.exe --list --online'.",
1959 + L"Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND"),
1960 + -1);
1961 }
1962
1963 WSL2_TEST_METHOD(TestExistingSwapVhd)
@@ -2288,16 +2282,20 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
2282
2283 validateWarnings(
2284 L"networkingMode=bridged",
2291 - L"wsl: Bridged networking requires wsl2.vmSwitch to be set.\r\n"
2292 - L"Error code: CreateInstance/CreateVm/ConfigureNetworking/WSL_E_VMSWITCH_NOT_SET\r\n"
2293 - L"wsl: Failed to configure network (networkingMode Bridged), falling back to networkingMode None.\r\n",
2285 + L"wsl: " +
2286 + FormatErrorMessage(
2287 + L"Bridged networking requires wsl2.vmSwitch to be set.",
2288 + L"CreateInstance/CreateVm/ConfigureNetworking/WSL_E_VMSWITCH_NOT_SET") +
2289 + L"wsl: Failed to configure network (networkingMode Bridged), falling back to networkingMode None.\r\n",
2290 L"[wsl2]\n");
2291
2292 validateWarnings(
2293 L"networkingMode=bridged\nvmSwitch=DoesNotExist",
2298 - L"wsl: The VmSwitch 'DoesNotExist' was not found. Available switches:*\r\n"
2299 - L"Error code: CreateInstance/CreateVm/ConfigureNetworking/WSL_E_VMSWITCH_NOT_FOUND\r\n"
2300 - L"wsl: Failed to configure network (networkingMode Bridged), falling back to networkingMode None.\r\n",
2294 + L"wsl: " +
2295 + FormatErrorMessage(
2296 + L"The VmSwitch 'DoesNotExist' was not found. Available switches:*",
2297 + L"CreateInstance/CreateVm/ConfigureNetworking/WSL_E_VMSWITCH_NOT_FOUND") +
2298 + L"wsl: Failed to configure network (networkingMode Bridged), falling back to networkingMode None.\r\n",
2299 L"[wsl2]\n",
2300 true);
2301
@@ -2511,9 +2509,9 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
2509 std::tie(output, warnings) = LxsstuLaunchWslAndCaptureOutput(L"--system echo not ok", -1);
2510
2511 const std::wstring configPath = wsl::windows::common::helpers::GetWslConfigPath();
2514 - const auto expectedOutput =
2515 - L"GUI application support is disabled via " + configPath +
2516 - L" or /etc/wsl.conf.\r\nError code: Wsl/Service/CreateInstance/WSL_E_GUI_APPLICATIONS_DISABLED\r\n";
2512 + const auto expectedOutput = FormatErrorMessage(
2513 + L"GUI application support is disabled via " + configPath + L" or /etc/wsl.conf.",
2514 + L"Wsl/Service/CreateInstance/WSL_E_GUI_APPLICATIONS_DISABLED");
2515
2516 VERIFY_ARE_EQUAL(output, expectedOutput);
2517 VERIFY_ARE_EQUAL(L"", warnings);
@@ -2678,11 +2676,12 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
2676 // Attempt to import a vhd with an open handle.
2677 validateOutput(
2678 std::format(L"--import-in-place test-distro-corrupted \"{}\"", vhdPath.wstring()),
2681 - std::format(
2682 - L"Failed to attach disk '\\\\?\\{}' to WSL2: The process cannot access the file because it is being used by "
2683 - L"another process. \r\n"
2684 - L"Error code: Wsl/Service/RegisterDistro/MountDisk/HCS/ERROR_SHARING_VIOLATION\r\n",
2685 - vhdPath.wstring()));
2679 + FormatErrorMessage(
2680 + std::format(
2681 + L"Failed to attach disk '\\\\?\\{}' to WSL2: The process cannot access the file because it is being used by "
2682 + L"another process. ",
2683 + vhdPath.wstring()),
2684 + L"Wsl/Service/RegisterDistro/MountDisk/HCS/ERROR_SHARING_VIOLATION"));
2685
2686 vhd.reset();
2687
@@ -2707,14 +2706,16 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
2706 // Validate that starting the distribution fails with the correct error code.
2707 validateOutput(
2708 L"-d BrokenDistro echo ok",
2710 - L"The distribution failed to start because its virtual disk is corrupted.\r\n"
2711 - L"Error code: Wsl/Service/CreateInstance/WSL_E_DISK_CORRUPTED\r\n");
2709 + FormatErrorMessage(
2710 + L"The distribution failed to start because its virtual disk is corrupted.",
2711 + L"Wsl/Service/CreateInstance/WSL_E_DISK_CORRUPTED"));
2712
2713 // Validate that trying to export the distribution fails with the correct error code.
2714 validateOutput(
2715 L"--export BrokenDistro dummy.tar",
2716 - L"The distribution failed to start because its virtual disk is corrupted.\r\n"
2717 - L"Error code: Wsl/Service/WSL_E_DISK_CORRUPTED\r\n");
2716 + FormatErrorMessage(
2717 + L"The distribution failed to start because its virtual disk is corrupted.",
2718 + L"Wsl/Service/WSL_E_DISK_CORRUPTED"));
2719
2720 // Shutdown WSL to force the disk to detach.
2721 VERIFY_ARE_EQUAL(LxsstuLaunchWsl(L"--shutdown"), 0L);
@@ -2723,8 +2724,9 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
2724 // Import a corrupted vhd.
2725 validateOutput(
2726 std::format(L"--import-in-place test-distro-corrupted \"{}\"", vhdPath.wstring()),
2726 - L"The distribution failed to start because its virtual disk is corrupted.\r\n"
2727 - L"Error code: Wsl/Service/RegisterDistro/WSL_E_DISK_CORRUPTED\r\n");
2727 + FormatErrorMessage(
2728 + L"The distribution failed to start because its virtual disk is corrupted.",
2729 + L"Wsl/Service/RegisterDistro/WSL_E_DISK_CORRUPTED"));
2730
2731 // Ensure the VHD can be deleted to make sure it was properly ejected from the VM.
2732 VERIFY_ARE_EQUAL(DeleteFileW(vhdPath.c_str()), TRUE);
@@ -2941,17 +2943,17 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
2943 WslConfigChange configChange(LxssGenerateTestConfig({.kernel = nonExistentFile.c_str()}));
2944 ValidateOutput(
2945 L"echo ok",
2944 - std::format(
2945 - L"{}\r\nError code: Wsl/Service/CreateInstance/CreateVm/WSL_E_CUSTOM_KERNEL_NOT_FOUND\r\n",
2946 - wsl::shared::Localization::MessageCustomKernelNotFound(wslConfigPath, nonExistentFile)),
2946 + FormatErrorMessage(
2947 + wsl::shared::Localization::MessageCustomKernelNotFound(wslConfigPath, nonExistentFile),
2948 + L"Wsl/Service/CreateInstance/CreateVm/WSL_E_CUSTOM_KERNEL_NOT_FOUND"),
2949 L"");
2950
2951 configChange.Update(LxssGenerateTestConfig({.kernelModules = nonExistentFile.c_str()}));
2952 ValidateOutput(
2953 L"echo ok",
2952 - std::format(
2953 - L"{}\r\nError code: Wsl/Service/CreateInstance/CreateVm/WSL_E_CUSTOM_KERNEL_NOT_FOUND\r\n",
2954 - wsl::shared::Localization::MessageCustomKernelModulesNotFound(wslConfigPath, nonExistentFile)),
2954 + FormatErrorMessage(
2955 + wsl::shared::Localization::MessageCustomKernelModulesNotFound(wslConfigPath, nonExistentFile),
2956 + L"Wsl/Service/CreateInstance/CreateVm/WSL_E_CUSTOM_KERNEL_NOT_FOUND"),
2957 L"");
2958
2959 #ifdef WSL_DEV_INSTALL_PATH
@@ -2981,9 +2983,9 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
2983 configChange.Update(LxssGenerateTestConfig({.kernelModules = kernelModulesPath.c_str()}));
2984 ValidateOutput(
2985 L"echo ok",
2984 - std::format(
2985 - L"{}\r\nError code: Wsl/Service/CreateInstance/CreateVm/WSL_E_CUSTOM_KERNEL_NOT_FOUND\r\n",
2986 - wsl::shared::Localization::MessageMismatchedKernelModulesError()),
2986 + FormatErrorMessage(
2987 + wsl::shared::Localization::MessageMismatchedKernelModulesError(),
2988 + L"Wsl/Service/CreateInstance/CreateVm/WSL_E_CUSTOM_KERNEL_NOT_FOUND"),
2989 L"");
2990
2991 configChange.Update(LxssGenerateTestConfig());
@@ -3132,8 +3134,8 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
3134
3135 VERIFY_ARE_EQUAL(
3136 out,
3135 - L"The supplied install location is already in use.\r\nError code: "
3136 - L"Wsl/Service/MoveDistro/ERROR_FILE_EXISTS\r\n");
3137 + FormatErrorMessage(
3138 + L"The supplied install location is already in use.", L"Wsl/Service/MoveDistro/ERROR_FILE_EXISTS"));
3139 // Validate that the distribution still starts and that the vhd hasn't moved.
3140 validateDistro();
3141 VERIFY_IS_TRUE(std::filesystem::exists(std::format(L"{}\\ext4.vhdx", absolutePath)));
@@ -3147,8 +3149,9 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
3149
3150 VERIFY_ARE_EQUAL(
3151 out,
3150 - L"The filename, directory name, or volume label syntax is incorrect. \r\nError code: "
3151 - L"Wsl/Service/MoveDistro/ERROR_INVALID_NAME\r\n");
3152 + FormatErrorMessage(
3153 + L"The filename, directory name, or volume label syntax is incorrect. ",
3154 + L"Wsl/Service/MoveDistro/ERROR_INVALID_NAME"));
3155 // Validate that the distribution still starts and that the vhd hasn't moved.
3156 validateDistro();
3157 VERIFY_IS_TRUE(std::filesystem::exists(std::format(L"{}\\ext4.vhdx", absolutePath)));
@@ -3309,9 +3312,10 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
3312 auto cleanupName =
3313 wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [name]() { LxsstuLaunchWsl(std::format(L"--unregister {}", name)); });
3314
3312 - auto validateDistro = [name](LPCWSTR size, LPCWSTR expectedSize, LPCWSTR expectedError = nullptr) {
3313 - auto [out, _] = LxsstuLaunchWslAndCaptureOutput(std::format(L"--manage {} --resize {}", name, size), expectedError ? -1 : 0);
3314 - if (expectedError)
3315 + auto validateDistro = [name](LPCWSTR size, LPCWSTR expectedSize, const std::wstring& expectedError = {}) {
3316 + auto [out, _] =
3317 + LxsstuLaunchWslAndCaptureOutput(std::format(L"--manage {} --resize {}", name, size), expectedError.empty() ? 0 : -1);
3318 + if (!expectedError.empty())
3319 {
3320 VERIFY_ARE_EQUAL(expectedError, out);
3321 return;
@@ -3324,14 +3328,16 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
3328
3329 validateDistro(L"1500G", L"1.5T");
3330 validateDistro(L"500G", L"492G");
3327 - validateDistro(L"1M", nullptr, L"Failed to resize disk.\r\nError code: Wsl/Service/E_FAIL\r\n");
3331 + validateDistro(L"1M", nullptr, FormatErrorMessage(L"Failed to resize disk.", L"Wsl/Service/E_FAIL"));
3332
3333 {
3334 WslKeepAlive keepAlive;
3335 auto [out, _] = LxsstuLaunchWslAndCaptureOutput(L"--manage test_distro --resize 1500GB", -1);
3336 VERIFY_ARE_EQUAL(
3333 - L"The operation could not be completed because the VHD is currently in use. To force WSL to stop use: wsl.exe "
3334 - L"--shutdown\r\nError code: Wsl/Service/WSL_E_DISTRO_NOT_STOPPED\r\n",
3337 + FormatErrorMessage(
3338 + L"The operation could not be completed because the VHD is currently in use. To force WSL "
3339 + L"to stop use: wsl.exe --shutdown",
3340 + L"Wsl/Service/WSL_E_DISTRO_NOT_STOPPED"),
3341 out);
3342 }
3343 }
@@ -4368,7 +4374,7 @@ localhostForwarding=true
4374 auto [out, _] = LxsstuLaunchWslAndCaptureOutput(L"--manage nonexistent --set-default-user root", -1);
4375
4376 VERIFY_ARE_EQUAL(
4371 - out, L"There is no distribution with the supplied name.\r\nError code: Wsl/Service/WSL_E_DISTRO_NOT_FOUND\r\n");
4377 + out, FormatErrorMessage(L"There is no distribution with the supplied name.", L"Wsl/Service/WSL_E_DISTRO_NOT_FOUND"));
4378
4379 constexpr auto injectionMarker = L"/tmp/wsl-manage-default-user-injection";
4380 LxsstuLaunchWsl(std::format(L"-u root -e /usr/bin/rm -f {}", injectionMarker));
@@ -4615,7 +4621,7 @@ VERSION_ID="Invalid|Format"
4621 const auto testDistroId = GetDistributionId(LXSS_DISTRO_NAME_TEST_L);
4622 VERIFY_IS_TRUE(testDistroId.has_value());
4623
4618 - auto validateOutput = [](const std::wstring& Cmd, LPCWSTR ExpectedOutput, int ExitCode = 0) {
4624 + auto validateOutput = [](const std::wstring& Cmd, const std::wstring& ExpectedOutput, int ExitCode = 0) {
4625 auto [out, _] = LxsstuLaunchWslAndCaptureOutput(Cmd, ExitCode);
4626
4627 VERIFY_ARE_EQUAL(out, ExpectedOutput);
@@ -4639,11 +4645,12 @@ VERSION_ID="Invalid|Format"
4645 wsl::shared::string::GuidToString<wchar_t>(testDistroId.value(), wsl::shared::string::GuidToStringFlags::Uppercase)),
4646 L"OK");
4647
4642 - validateOutput(L"--distribution-id InvalidGuid", L"The parameter is incorrect. \r\nError code: Wsl/E_INVALIDARG\r\n", -1);
4648 + validateOutput(L"--distribution-id InvalidGuid", FormatErrorMessage(L"The parameter is incorrect. ", L"Wsl/E_INVALIDARG"), -1);
4649 validateOutput(
4650 L"--distribution-id {C13B2B63-F9D5-4840-8105-F6ABECCF46CA}",
4645 - L"There is no distribution with the supplied name.\r\nError code: "
4646 - L"Wsl/Service/CreateInstance/ReadDistroConfig/WSL_E_DISTRO_NOT_FOUND\r\n",
4651 + FormatErrorMessage(
4652 + L"There is no distribution with the supplied name.",
4653 + L"Wsl/Service/CreateInstance/ReadDistroConfig/WSL_E_DISTRO_NOT_FOUND"),
4654 -1);
4655 }
4656
@@ -4953,12 +4960,13 @@ VERSION_ID="Invalid|Format"
4960 CreateTarFromManifest(L"", L"distro-no-default-name.tar");
4961
4962 // Import should fail without --name
4956 - constexpr auto expectedOutput =
4957 - L"Installing: distro-no-default-name.tar\r\n\
4958 -This distribution doesn't contain a default name. Use --name to choose the distribution name.\r\n\
4959 -Error code: Wsl/Service/RegisterDistro/WSL_E_DISTRIBUTION_NAME_NEEDED\r\n";
4963 + const auto expectedOutput = L"Installing: distro-no-default-name.tar\r\n" +
4964 + FormatErrorMessage(
4965 + L"This distribution doesn't contain a default name. Use --name to choose the "
4966 + L"distribution name.",
4967 + L"Wsl/Service/RegisterDistro/WSL_E_DISTRIBUTION_NAME_NEEDED");
4968
4961 - InstallFromTar(L"distro-no-default-name.tar", L"", -1, expectedOutput);
4969 + InstallFromTar(L"distro-no-default-name.tar", L"", -1, expectedOutput.c_str());
4970
4971 // And succeed with --name
4972 InstallFromTar(L"distro-no-default-name.tar", L"--name test-distro-no-default-name");
@@ -5212,12 +5220,13 @@ Error code: Wsl/Service/RegisterDistro/WSL_E_DISTRIBUTION_NAME_NEEDED\r\n";
5220
5221 CreateTarFromManifest(L"[oobe]\ndefaultName = test_distro", L"conflict.tar");
5222
5215 - constexpr auto expectedOutput =
5216 - L"Installing: conflict.tar\r\n\
5217 -A distribution with the supplied name already exists. Use --name to choose a different name.\r\n\
5218 -Error code: Wsl/Service/RegisterDistro/ERROR_ALREADY_EXISTS\r\n";
5223 + const auto expectedOutput = L"Installing: conflict.tar\r\n" +
5224 + FormatErrorMessage(
5225 + L"A distribution with the supplied name already exists. Use --name to choose a "
5226 + L"different name.",
5227 + L"Wsl/Service/RegisterDistro/ERROR_ALREADY_EXISTS");
5228
5220 - InstallFromTar(L"conflict.tar", L"", -1, expectedOutput);
5229 + InstallFromTar(L"conflict.tar", L"", -1, expectedOutput.c_str());
5230 }
5231
5232 // Distribution default name is invalid
@@ -5226,12 +5235,11 @@ Error code: Wsl/Service/RegisterDistro/ERROR_ALREADY_EXISTS\r\n";
5235
5236 CreateTarFromManifest(L"[oobe]\ndefaultName = invalid!", L"invalid.tar");
5237
5229 - constexpr auto expectedOutput =
5230 - L"Installing: invalid.tar\r\n\
5231 -Invalid distribution name: \"invalid!\".\r\n\
5232 -Error code: Wsl/Service/RegisterDistro/E_INVALIDARG\r\n";
5238 + const auto expectedOutput =
5239 + L"Installing: invalid.tar\r\n" +
5240 + FormatErrorMessage(L"Invalid distribution name: \"invalid!\".", L"Wsl/Service/RegisterDistro/E_INVALIDARG");
5241
5234 - InstallFromTar(L"invalid.tar", L"", -1, expectedOutput);
5242 + InstallFromTar(L"invalid.tar", L"", -1, expectedOutput.c_str());
5243 }
5244
5245 // Distribution icon file is too big
@@ -5604,9 +5612,10 @@ Error code: Wsl/Service/RegisterDistro/E_INVALIDARG\r\n";
5612
5613 ValidateInstallError(
5614 L"--install DoesNotExists",
5607 - L"Invalid distribution name: 'DoesNotExists'.\r\n\
5608 -To get a list of valid distributions, use 'wsl.exe --list --online'.\r\n\
5609 -Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND\r\n");
5615 + FormatErrorMessage(
5616 + L"Invalid distribution name: 'DoesNotExists'.\r\nTo get a list of valid distributions, use 'wsl.exe "
5617 + L"--list --online'.",
5618 + L"Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND"));
5619
5620 VERIFY_ARE_EQUAL(LxsstuLaunchWsl(L"--unregister debian-12"), 0L);
5621
@@ -5750,16 +5759,16 @@ Distribution successfully installed. It can be launched via 'wsl.exe -d ubuntu-d
5759 // There's no easy way to automate the appx package installation, but verify that we take the legacy path
5760 ValidateInstallError(
5761 L"--install legacy --no-launch --web-download",
5753 - L"Downloading: legacy\r\n\
5754 -A connection with the server could not be established \r\n\
5755 -Error code: Wsl/InstallDistro/WININET_E_CANNOT_CONNECT\r\n",
5762 + L"Downloading: legacy\r\n" +
5763 + FormatErrorMessage(
5764 + L"A connection with the server could not be established ", L"Wsl/InstallDistro/WININET_E_CANNOT_CONNECT"),
5765 L"wsl: Using legacy distribution registration. Consider using a tar based distribution instead.\r\n");
5766
5767 ValidateInstallError(
5768 L"--install legacy --no-launch --web-download --legacy",
5760 - L"Downloading: legacy\r\n\
5761 -A connection with the server could not be established \r\n\
5762 -Error code: Wsl/InstallDistro/WININET_E_CANNOT_CONNECT\r\n",
5769 + L"Downloading: legacy\r\n" +
5770 + FormatErrorMessage(
5771 + L"A connection with the server could not be established ", L"Wsl/InstallDistro/WININET_E_CANNOT_CONNECT"),
5772 L"wsl: Using legacy distribution registration. Consider using a tar based distribution instead.\r\n");
5773 }
5774
@@ -5801,9 +5810,9 @@ Error code: Wsl/InstallDistro/WININET_E_CANNOT_CONNECT\r\n",
5810 // Validate that --legacy takes the appx path.
5811 ValidateInstallError(
5812 L"--install debian-12 --no-launch --web-download --legacy",
5804 - L"Downloading: debian-12\r\n\
5805 -A connection with the server could not be established \r\n\
5806 -Error code: Wsl/InstallDistro/WININET_E_CANNOT_CONNECT\r\n",
5813 + L"Downloading: debian-12\r\n" +
5814 + FormatErrorMessage(
5815 + L"A connection with the server could not be established ", L"Wsl/InstallDistro/WININET_E_CANNOT_CONNECT"),
5816 L"wsl: Using legacy distribution registration. Consider using a tar based distribution instead.\r\n");
5817 }
5818
@@ -5921,11 +5930,10 @@ Error code: Wsl/InstallDistro/WININET_E_CANNOT_CONNECT\r\n",
5930
5931 ValidateInstallError(
5932 L"--install debian-12",
5924 - std::format(
5925 - L"Installing: DebianFriendlyName\r\n\
5926 -The distribution hash doesn't match. Expected: 0x12, actual hash: {}\r\n\
5927 -Error code: Wsl/InstallDistro/VerifyChecksum/TRUST_E_BAD_DIGEST\r\n",
5928 - wsl::shared::string::MultiByteToWide(tarHash)),
5933 + L"Installing: DebianFriendlyName\r\n" +
5934 + FormatErrorMessage(
5935 + std::format(L"The distribution hash doesn't match. Expected: 0x12, actual hash: {}", wsl::shared::string::MultiByteToWide(tarHash)),
5936 + L"Wsl/InstallDistro/VerifyChecksum/TRUST_E_BAD_DIGEST"),
5937 L"");
5938 }
5939
@@ -5952,9 +5960,8 @@ Error code: Wsl/InstallDistro/VerifyChecksum/TRUST_E_BAD_DIGEST\r\n",
5960
5961 ValidateInstallError(
5962 L"--install debian-12",
5955 - L"Installing: DebianFriendlyName\r\n\
5956 -Invalid hex string: wrongformat\r\n\
5957 -Error code: Wsl/InstallDistro/VerifyChecksum/E_INVALIDARG\r\n",
5963 + L"Installing: DebianFriendlyName\r\n" +
5964 + FormatErrorMessage(L"Invalid hex string: wrongformat", L"Wsl/InstallDistro/VerifyChecksum/E_INVALIDARG"),
5965 L"");
5966 }
5967
@@ -5989,9 +5996,10 @@ Error code: Wsl/InstallDistro/VerifyChecksum/E_INVALIDARG\r\n",
5996
5997 ValidateInstallError(
5998 L"--install invalid",
5992 - L"Invalid distribution name: 'invalid'.\r\n\
5993 -To get a list of valid distributions, use 'wsl.exe --list --online'.\r\n\
5994 -Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND\r\n",
5999 + FormatErrorMessage(
6000 + L"Invalid distribution name: 'invalid'.\r\nTo get a list of valid distributions, use 'wsl.exe --list "
6001 + L"--online'.",
6002 + L"Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND"),
6003 L"");
6004 }
6005
@@ -6029,8 +6037,8 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND\r\n",
6037
6038 VERIFY_ARE_EQUAL(
6039 out,
6032 - L"Cannot create a file when that file already exists. \r\n"
6033 - L"Error code: Wsl/InstallDistro/ERROR_ALREADY_EXISTS\r\n");
6040 + FormatErrorMessage(
6041 + L"Cannot create a file when that file already exists. ", L"Wsl/InstallDistro/ERROR_ALREADY_EXISTS"));
6042
6043 VERIFY_ARE_EQUAL(err, L"");
6044 }
@@ -6040,8 +6048,8 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND\r\n",
6048
6049 VERIFY_ARE_EQUAL(
6050 out,
6043 - L"Cannot create a file when that file already exists. \r\n"
6044 - L"Error code: Wsl/InstallDistro/ERROR_ALREADY_EXISTS\r\n");
6051 + FormatErrorMessage(
6052 + L"Cannot create a file when that file already exists. ", L"Wsl/InstallDistro/ERROR_ALREADY_EXISTS"));
6053
6054 VERIFY_ARE_EQUAL(err, L"");
6055 }
@@ -6068,8 +6076,9 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND\r\n",
6076 auto restore = SetManifest(manifest);
6077 ValidateInstallError(
6078 L"--install",
6071 - L"No default distribution has been configured. Please provide a distribution to install.\r\n\
6072 -Error code: Wsl/InstallDistro/E_UNEXPECTED\r\n",
6079 + FormatErrorMessage(
6080 + L"No default distribution has been configured. Please provide a distribution to install.",
6081 + L"Wsl/InstallDistro/E_UNEXPECTED"),
6082 L"");
6083 }
6084
@@ -6079,8 +6088,10 @@ Error code: Wsl/InstallDistro/E_UNEXPECTED\r\n",
6088
6089 ValidateInstallError(
6090 L"--install debian",
6082 - L"Invalid JSON document. Parse error: [json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'B'\r\n\
6083 -Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n",
6091 + FormatErrorMessage(
6092 + L"Invalid JSON document. Parse error: [json.exception.parse_error.101] parse error at line 1, column 1: "
6093 + L"syntax error while parsing value - invalid literal; last read: 'B'",
6094 + L"Wsl/InstallDistro/WSL_E_INVALID_JSON"),
6095 L"");
6096 }
6097
@@ -6910,8 +6921,9 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n",
6921
6922 VERIFY_ARE_EQUAL(
6923 out,
6913 - L"The imported file is not a valid Linux distribution.\r\nError code: "
6914 - L"Wsl/Service/RegisterDistro/WSL_E_NOT_A_LINUX_DISTRO\r\n");
6924 + FormatErrorMessage(
6925 + L"The imported file is not a valid Linux distribution.",
6926 + L"Wsl/Service/RegisterDistro/WSL_E_NOT_A_LINUX_DISTRO"));
6927
6928 // TODO: Uncomment once SetVersionDebug is removed from the tests .wslconfig.
6929 // VERIFY_ARE_EQUAL(err, L"");
@@ -6923,8 +6935,9 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n",
6935
6936 VERIFY_ARE_EQUAL(
6937 out,
6926 - L"Installing: NUL\r\nThe imported file is not a valid Linux distribution.\r\nError code: "
6927 - L"Wsl/Service/RegisterDistro/WSL_E_NOT_A_LINUX_DISTRO\r\n");
6938 + L"Installing: NUL\r\n" + FormatErrorMessage(
6939 + L"The imported file is not a valid Linux distribution.",
6940 + L"Wsl/Service/RegisterDistro/WSL_E_NOT_A_LINUX_DISTRO"));
6941 // TODO: Uncomment once SetVersionDebug is removed from the tests .wslconfig.
6942 // VERIFY_ARE_EQUAL(err, L"");
6943 }
@@ -6946,8 +6959,9 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n",
6959
6960 VERIFY_ARE_EQUAL(
6961 out,
6949 - L"The imported file is not a valid Linux distribution.\r\nError code: "
6950 - L"Wsl/Service/RegisterDistro/WSL_E_NOT_A_LINUX_DISTRO\r\n");
6962 + FormatErrorMessage(
6963 + L"The imported file is not a valid Linux distribution.",
6964 + L"Wsl/Service/RegisterDistro/WSL_E_NOT_A_LINUX_DISTRO"));
6965 // TODO: Uncomment once SetVersionDebug is removed from the tests .wslconfig.
6966 // VERIFY_ARE_EQUAL(err, L"");
6967 }
@@ -7113,7 +7127,8 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n",
7127 auto [out, err] =
7128 LxsstuLaunchWslAndCaptureOutput(std::format(L"--export {} {} --format vhd", LXSS_DISTRO_NAME_TEST_L, vhdPath), -1);
7129 VERIFY_ARE_EQUAL(
7116 - out, L"The specified file must have the .vhdx file extension.\r\nError code: Wsl/Service/WSL_E_EXPORT_FAILED\r\n");
7130 + out,
7131 + FormatErrorMessage(L"The specified file must have the .vhdx file extension.", L"Wsl/Service/WSL_E_EXPORT_FAILED"));
7132 VERIFY_ARE_EQUAL(err, L"");
7133
7134 // Export the distribution to a .vhdx.
@@ -7139,7 +7154,7 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n",
7154 // Attempt to export to a .vhdx (should fail).
7155 std::tie(out, err) = LxsstuLaunchWslAndCaptureOutput(std::format(L"--export {} {} --format vhd", newDistroName, vhdxPath), -1);
7156 VERIFY_ARE_EQUAL(
7142 - out, L"The specified file must have the .vhd file extension.\r\nError code: Wsl/Service/WSL_E_EXPORT_FAILED\r\n");
7157 + out, FormatErrorMessage(L"The specified file must have the .vhd file extension.", L"Wsl/Service/WSL_E_EXPORT_FAILED"));
7158 VERIFY_ARE_EQUAL(err, L"");
7159
7160 // Attempt to import to a non VHD file.
@@ -7153,8 +7168,9 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n",
7168 std::format(L"--import {} {} {} --vhd", negativeVariationDistro, negativeVariationDistro, tempFile.Path), -1);
7169 VERIFY_ARE_EQUAL(
7170 out,
7156 - L"The specified file must have the .vhd or .vhdx file extension.\r\nError code: "
7157 - L"Wsl/Service/RegisterDistro/WSL_E_IMPORT_FAILED\r\n");
7171 + FormatErrorMessage(
7172 + L"The specified file must have the .vhd or .vhdx file extension.",
7173 + L"Wsl/Service/RegisterDistro/WSL_E_IMPORT_FAILED"));
7174 VERIFY_ARE_EQUAL(err, L"");
7175 }
7176
test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp
+2 -1
@@ -116,7 +116,8 @@ class WSLCE2EContainerAttachTests
116 {
117 auto result = RunWslc(std::format(L"container attach {}", WslcContainerName));
118 result.Verify(
119 - {.Stderr = std::format(L"Container '{}' not found.\r\nError code: WSLC_E_CONTAINER_NOT_FOUND\r\n", WslcContainerName),
119 + {.Stderr =
120 + FormatErrorMessage(std::format(L"Container '{}' not found.", WslcContainerName), L"WSLC_E_CONTAINER_NOT_FOUND"),
121 .ExitCode = 1});
122 }
123
test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp
+36 -20
@@ -97,11 +97,11 @@ class WSLCE2EContainerCreateTests
97
98 auto result = RunWslc(std::format(L"container create --name {} {}", WslcContainerName, reference));
99
100 - std::wstringstream expectedError;
101 - expectedError << L"Image '" << reference << L"' not found, pulling\r\n"
102 - << L"manifest for " << reference << L" not found: manifest unknown: manifest unknown\r\n"
103 - << L"Error code: WSLC_E_IMAGE_NOT_FOUND\r\n";
104 - result.Verify({.Stderr = expectedError.str(), .ExitCode = 1});
100 + const auto expectedError = std::format(L"Image '{}' not found, pulling\r\n", reference) +
101 + FormatErrorMessage(
102 + std::format(L"manifest for {} not found: manifest unknown: manifest unknown", reference),
103 + L"WSLC_E_IMAGE_NOT_FOUND");
104 + result.Verify({.Stderr = expectedError, .ExitCode = 1});
105 }
106
107 WSLC_TEST_METHOD(WSLCE2E_Container_Create_PullPolicy)
@@ -120,8 +120,9 @@ class WSLCE2EContainerCreateTests
120 EnsureContainerDoesNotExist(WslcContainerName);
121
122 result = RunWslc(std::format(L"container create --pull=always --name {} {}", WslcContainerName, registryImage));
123 - const auto errorMessage = std::format(
124 - L"manifest for {} not found: manifest unknown: manifest unknown\r\nError code: WSLC_E_IMAGE_NOT_FOUND\r\n", registryImage);
123 + const auto errorMessage = FormatErrorMessage(
124 + std::format(L"manifest for {} not found: manifest unknown: manifest unknown", registryImage),
125 + L"WSLC_E_IMAGE_NOT_FOUND");
126 result.Verify({.Stdout = L"", .Stderr = errorMessage, .ExitCode = 1});
127 VerifyContainerIsNotListed(WslcContainerName);
128
@@ -171,7 +172,8 @@ class WSLCE2EContainerCreateTests
172 auto result = RunWslc(std::format(
173 L"container create --cidfile \"{}\" --name {} {}", EscapePath(cidFilePath.wstring()), WslcContainerName, DebianImage.NameAndTag()));
174 result.Verify(
174 - {.Stderr = std::format(L"CID file '{}' already exists\r\nError code: ERROR_FILE_EXISTS\r\n", EscapePath(cidFilePath.wstring())),
175 + {.Stderr = FormatErrorMessage(
176 + std::format(L"CID file '{}' already exists", EscapePath(cidFilePath.wstring())), L"ERROR_FILE_EXISTS"),
177 .ExitCode = 1});
178
179 VerifyContainerIsNotListed(WslcContainerName);
@@ -189,7 +191,13 @@ class WSLCE2EContainerCreateTests
191 // Attempt to create another container with the same name
192 result = RunWslc(std::format(L"container create --name {} {}", WslcContainerName, DebianImage.NameAndTag()));
193 result.Verify(
192 - {.Stderr = std::format(L"Conflict. The container name \"/{}\" is already in use by container \"{}\". You have to remove (or rename) that container to be able to reuse that name.\r\nError code: ERROR_ALREADY_EXISTS\r\n", WslcContainerName, containerId),
194 + {.Stderr = FormatErrorMessage(
195 + std::format(
196 + L"Conflict. The container name \"/{}\" is already in use by container \"{}\". You have to remove "
197 + L"(or rename) that container to be able to reuse that name.",
198 + WslcContainerName,
199 + containerId),
200 + L"ERROR_ALREADY_EXISTS"),
201 .ExitCode = 1});
202 }
203
@@ -632,7 +640,9 @@ class WSLCE2EContainerCreateTests
640
641 result = RunWslc(std::format(L"container start -a {}", WslcContainerName));
642 result.Verify(
635 - {.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});
643 + {.Stderr =
644 + FormatErrorMessage(L"unable to find user user_does_not_exist: no matching entries in passwd file", L"E_FAIL"),
645 + .ExitCode = 1});
646 }
647
648 WSLC_TEST_METHOD(WSLCE2E_Container_Create_Tmpfs)
@@ -778,7 +788,10 @@ class WSLCE2EContainerCreateTests
788 WslcContainerName,
789 source.wstring(),
790 AlpineImage.NameAndTag()));
781 - result.Verify({.Stdout = L"", .Stderr = FormatWslcError(Localization::MessageWslcBindSourcePathNotFound(source.wstring())), .ExitCode = 1});
791 + result.Verify(
792 + {.Stdout = L"",
793 + .Stderr = FormatErrorMessage(Localization::MessageWslcBindSourcePathNotFound(source.wstring()), L"E_INVALIDARG"),
794 + .ExitCode = 1});
795 VERIFY_IS_FALSE(std::filesystem::exists(source));
796 EnsureContainerDoesNotExist(WslcContainerName);
797 }
@@ -922,7 +935,10 @@ class WSLCE2EContainerCreateTests
935 {
936 const auto result =
937 RunWslc(std::format(L"container create --name {} {} {} true", WslcContainerName, arguments, DebianImage.NameAndTag()));
925 - result.Verify({.Stdout = L"", .Stderr = FormatWslcError(Localization::WSLCCLI_DuplicateMountDestinationError(L"/data")), .ExitCode = 1});
938 + result.Verify(
939 + {.Stdout = L"",
940 + .Stderr = FormatErrorMessage(Localization::WSLCCLI_DuplicateMountDestinationError(L"/data"), L"E_INVALIDARG"),
941 + .ExitCode = 1});
942 EnsureContainerDoesNotExist(WslcContainerName);
943 }
944 }
@@ -1094,7 +1110,7 @@ class WSLCE2EContainerCreateTests
1110 {
1111 auto result =
1112 RunWslc(std::format(L"container create --stop-timeout -2 --name {} {}", WslcContainerName, DebianImage.NameAndTag()));
1097 - result.Verify({.Stderr = L"Invalid stop timeout value: -2\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1});
1113 + result.Verify({.Stderr = FormatErrorMessage(L"Invalid stop timeout value: -2", L"E_INVALIDARG"), .ExitCode = 1});
1114 VerifyContainerIsNotListed(WslcContainerName);
1115 }
1116 }
@@ -1310,7 +1326,7 @@ class WSLCE2EContainerCreateTests
1326 {
1327 auto result = RunWslc(
1328 std::format(L"container create --network does-not-exist --name {} {} true", WslcContainerName, DebianImage.NameAndTag()));
1313 - result.Verify({.Stderr = L"Network not found: 'does-not-exist'\r\nError code: WSLC_E_NETWORK_NOT_FOUND\r\n", .ExitCode = 1});
1329 + result.Verify({.Stderr = FormatErrorMessage(L"Network not found: 'does-not-exist'", L"WSLC_E_NETWORK_NOT_FOUND"), .ExitCode = 1});
1330 VerifyContainerIsNotListed(WslcContainerName);
1331 }
1332
@@ -1369,8 +1385,8 @@ class WSLCE2EContainerCreateTests
1385 auto result =
1386 RunWslc(std::format(L"container create --network-alias db --name {} {} true", WslcContainerName, DebianImage.NameAndTag()));
1387 result.Verify(
1372 - {.Stderr =
1373 - L"Network aliases require a user-defined network. Use --network to specify one.\r\nError code: E_INVALIDARG\r\n",
1388 + {.Stderr = FormatErrorMessage(
1389 + L"Network aliases require a user-defined network. Use --network to specify one.", L"E_INVALIDARG"),
1390 .ExitCode = 1});
1391 VerifyContainerIsNotListed(WslcContainerName);
1392 }
@@ -1380,8 +1396,8 @@ class WSLCE2EContainerCreateTests
1396 auto result = RunWslc(std::format(
1397 L"container create --network none --network-alias db --name {} {} true", WslcContainerName, DebianImage.NameAndTag()));
1398 result.Verify(
1383 - {.Stderr =
1384 - L"Network aliases require a user-defined network. Use --network to specify one.\r\nError code: E_INVALIDARG\r\n",
1399 + {.Stderr = FormatErrorMessage(
1400 + L"Network aliases require a user-defined network. Use --network to specify one.", L"E_INVALIDARG"),
1401 .ExitCode = 1});
1402 VerifyContainerIsNotListed(WslcContainerName);
1403 }
@@ -1437,7 +1453,7 @@ class WSLCE2EContainerCreateTests
1453 auto result =
1454 RunWslc(std::format(L"container create --ip {} --name {} {} true", ipAddress, WslcContainerName, DebianImage.NameAndTag()));
1455 result.Verify(
1440 - {.Stderr = std::format(L"{}\r\nError code: E_INVALIDARG\r\n", wsl::shared::Localization::MessageWslcIpRequiresUserDefinedNetwork()),
1456 + {.Stderr = FormatErrorMessage(wsl::shared::Localization::MessageWslcIpRequiresUserDefinedNetwork(), L"E_INVALIDARG"),
1457 .ExitCode = 1});
1458 VerifyContainerIsNotListed(WslcContainerName);
1459 }
@@ -1449,7 +1465,7 @@ class WSLCE2EContainerCreateTests
1465 auto result = RunWslc(std::format(
1466 L"container create --network bridge --ip {} --name {} {} true", ipAddress, WslcContainerName, DebianImage.NameAndTag()));
1467 result.Verify(
1452 - {.Stderr = std::format(L"{}\r\nError code: E_INVALIDARG\r\n", wsl::shared::Localization::MessageWslcIpRequiresUserDefinedNetwork()),
1468 + {.Stderr = FormatErrorMessage(wsl::shared::Localization::MessageWslcIpRequiresUserDefinedNetwork(), L"E_INVALIDARG"),
1469 .ExitCode = 1});
1470 VerifyContainerIsNotListed(WslcContainerName);
1471 }
test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp
+4 -2
@@ -86,7 +86,8 @@ class WSLCE2EContainerExecTests
86 {
87 auto result = RunWslc(std::format(L"container exec {} echo hello", WslcContainerName));
88 result.Verify(
89 - {.Stderr = std::format(L"Container '{}' not found.\r\nError code: WSLC_E_CONTAINER_NOT_FOUND\r\n", WslcContainerName),
89 + {.Stderr =
90 + FormatErrorMessage(std::format(L"Container '{}' not found.", WslcContainerName), L"WSLC_E_CONTAINER_NOT_FOUND"),
91 .ExitCode = 1});
92 }
93
@@ -425,7 +426,8 @@ class WSLCE2EContainerExecTests
426
427 auto inspect = InspectContainer(WslcContainerName);
428 result = RunWslc(std::format(L"container exec {} echo should-fail", WslcContainerName));
428 - auto errorMessage = std::format(L"Container '{}' is not running.\r\nError code: WSLC_E_CONTAINER_NOT_RUNNING\r\n", inspect.Id);
429 + auto errorMessage =
430 + FormatErrorMessage(std::format(L"Container '{}' is not running.", inspect.Id), L"WSLC_E_CONTAINER_NOT_RUNNING");
431 result.Verify({.Stderr = errorMessage, .ExitCode = 1});
432 }
433
test/windows/wslc/e2e/WSLCE2EContainerKillTests.cpp
+2 -1
@@ -95,7 +95,8 @@ class WSLCE2EContainerKillTests
95
96 auto result = RunWslc(std::format(L"container kill {}", WslcContainerName));
97 result.Verify(
98 - {.Stderr = std::format(L"Container '{}' not found.\r\nError code: WSLC_E_CONTAINER_NOT_FOUND\r\n", WslcContainerName),
98 + {.Stderr =
99 + FormatErrorMessage(std::format(L"Container '{}' not found.", WslcContainerName), L"WSLC_E_CONTAINER_NOT_FOUND"),
100 .ExitCode = 1});
101 }
102
test/windows/wslc/e2e/WSLCE2EContainerRemoveTests.cpp
+2 -1
@@ -62,7 +62,8 @@ class WSLCE2EContainerRemoveTests
62 auto result = RunWslc(std::format(L"container remove {}", WslcContainerName));
63 result.Verify(
64 {.Stdout = L"",
65 - .Stderr = std::format(L"Container '{}' not found.\r\nError code: WSLC_E_CONTAINER_NOT_FOUND\r\n", WslcContainerName),
65 + .Stderr =
66 + FormatErrorMessage(std::format(L"Container '{}' not found.", WslcContainerName), L"WSLC_E_CONTAINER_NOT_FOUND"),
67 .ExitCode = 1});
68 }
69
test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp
+41 -24
@@ -108,8 +108,9 @@ class WSLCE2EContainerRunTests
108 VERIFY_IS_FALSE(result.Stdout->empty());
109
110 result = RunWslc(std::format(L"container run --pull=always --rm --name {} {}", WslcContainerName, registryImage));
111 - const auto errorMessage = std::format(
112 - L"manifest for {} not found: manifest unknown: manifest unknown\r\nError code: WSLC_E_IMAGE_NOT_FOUND\r\n", registryImage);
111 + const auto errorMessage = FormatErrorMessage(
112 + std::format(L"manifest for {} not found: manifest unknown: manifest unknown", registryImage),
113 + L"WSLC_E_IMAGE_NOT_FOUND");
114 result.Verify({.Stdout = L"", .Stderr = errorMessage, .ExitCode = 1});
115 VerifyContainerIsNotListed(WslcContainerName);
116
@@ -149,7 +150,8 @@ class WSLCE2EContainerRunTests
150 auto result = RunWslc(std::format(
151 L"container run --cidfile \"{}\" --name {} {}", EscapePath(cidFilePath.wstring()), WslcContainerName, DebianImage.NameAndTag()));
152 result.Verify(
152 - {.Stderr = std::format(L"CID file '{}' already exists\r\nError code: ERROR_FILE_EXISTS\r\n", EscapePath(cidFilePath.wstring())),
153 + {.Stderr = FormatErrorMessage(
154 + std::format(L"CID file '{}' already exists", EscapePath(cidFilePath.wstring())), L"ERROR_FILE_EXISTS"),
155 .ExitCode = 1});
156
157 VerifyContainerIsNotListed(WslcContainerName);
@@ -172,7 +174,13 @@ class WSLCE2EContainerRunTests
174 {
175 auto result = RunWslc(std::format(L"container run --rm --entrypoint /bin/does-not-exist {}", DebianImage.NameAndTag()));
176 result.Verify(
175 - {.Stdout = L"", .Stderr = L"failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: exec: \"/bin/does-not-exist\": stat /bin/does-not-exist: no such file or directory: unknown\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1});
177 + {.Stdout = L"",
178 + .Stderr = FormatErrorMessage(
179 + L"failed to create task for container: failed to create shim task: OCI runtime create failed: runc create "
180 + L"failed: unable to start container process: error during container init: exec: \"/bin/does-not-exist\": stat "
181 + L"/bin/does-not-exist: no such file or directory: unknown",
182 + L"E_INVALIDARG"),
183 + .ExitCode = 1});
184 }
185
186 WSLC_TEST_METHOD(WSLCE2E_Container_Run_Entrypoint_Detach_Lifecycle)
@@ -414,13 +422,15 @@ class WSLCE2EContainerRunTests
422 {
423 auto result = RunWslc(std::format(L"container run --rm -u user_does_not_exist {} id -u", DebianImage.NameAndTag()));
424 result.Verify(
417 - {.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});
425 + {.Stderr =
426 + FormatErrorMessage(L"unable to find user user_does_not_exist: no matching entries in passwd file", L"E_FAIL"),
427 + .ExitCode = 1});
428 }
429
430 WSLC_TEST_METHOD(WSLCE2E_Container_Run_UserOption_UnknownGroup_Fails)
431 {
432 auto result = RunWslc(std::format(L"container run --rm -u root:badgid {} id -u", DebianImage.NameAndTag()));
423 - result.Verify({.Stderr = L"unable to find group badgid: no matching entries in group file\r\nError code: E_FAIL\r\n", .ExitCode = 1});
433 + result.Verify({.Stderr = FormatErrorMessage(L"unable to find group badgid: no matching entries in group file", L"E_FAIL"), .ExitCode = 1});
434 }
435
436 WSLC_TEST_METHOD(WSLCE2E_Container_Run_UserOption_NameGroupRoot)
@@ -479,10 +489,12 @@ class WSLCE2EContainerRunTests
489 // Attempt to start — should fail with port conflict
490 auto startResult = RunWslc(std::format(L"container start {}", containerId));
491 startResult.Verify(
482 - {.Stderr = std::format(
483 - L"Failed to map port '127.0.0.1:{}/tcp', Only one usage of each socket address (protocol/network "
484 - L"address/port) is normally permitted. \r\nError code: WSAEADDRINUSE\r\n",
485 - HostTestPort1),
492 + {.Stderr = FormatErrorMessage(
493 + std::format(
494 + L"Failed to map port '127.0.0.1:{}/tcp', Only one usage of each socket address (protocol/network "
495 + L"address/port) is normally permitted. ",
496 + HostTestPort1),
497 + L"WSAEADDRINUSE"),
498 .ExitCode = 1});
499
500 // Clean up the created container
@@ -518,10 +530,12 @@ class WSLCE2EContainerRunTests
530 // Attempt to start — should fail with a port conflict, with the IPv6 address bracketed in the message.
531 auto ipv6StartResult = RunWslc(std::format(L"container start {}", ipv6ContainerId));
532 ipv6StartResult.Verify(
521 - {.Stderr = std::format(
522 - L"Failed to map port '[::1]:{}/tcp', Only one usage of each socket address (protocol/network "
523 - L"address/port) is normally permitted. \r\nError code: WSAEADDRINUSE\r\n",
524 - HostTestPort2),
533 + {.Stderr = FormatErrorMessage(
534 + std::format(
535 + L"Failed to map port '[::1]:{}/tcp', Only one usage of each socket address (protocol/network "
536 + L"address/port) is normally permitted. ",
537 + HostTestPort2),
538 + L"WSAEADDRINUSE"),
539 .ExitCode = 1});
540 }
541
@@ -944,7 +958,7 @@ class WSLCE2EContainerRunTests
958 {
959 auto result = RunWslc(std::format(
960 L"container run --rm --network does-not-exist --name {} {} true", WslcContainerName, DebianImage.NameAndTag()));
947 - result.Verify({.Stderr = L"Network not found: 'does-not-exist'\r\nError code: WSLC_E_NETWORK_NOT_FOUND\r\n", .ExitCode = 1});
961 + result.Verify({.Stderr = FormatErrorMessage(L"Network not found: 'does-not-exist'", L"WSLC_E_NETWORK_NOT_FOUND"), .ExitCode = 1});
962 }
963
964 WSLC_TEST_METHOD(WSLCE2E_Container_Run_NetworkAlias_Success)
@@ -1004,8 +1018,8 @@ class WSLCE2EContainerRunTests
1018 auto result =
1019 RunWslc(std::format(L"container run --rm --network-alias db --name {} {} true", WslcContainerName, DebianImage.NameAndTag()));
1020 result.Verify(
1007 - {.Stderr =
1008 - L"Network aliases require a user-defined network. Use --network to specify one.\r\nError code: E_INVALIDARG\r\n",
1021 + {.Stderr = FormatErrorMessage(
1022 + L"Network aliases require a user-defined network. Use --network to specify one.", L"E_INVALIDARG"),
1023 .ExitCode = 1});
1024 }
1025
@@ -1014,8 +1028,8 @@ class WSLCE2EContainerRunTests
1028 auto result = RunWslc(std::format(
1029 L"container run --rm --network none --network-alias db --name {} {} true", WslcContainerName, DebianImage.NameAndTag()));
1030 result.Verify(
1017 - {.Stderr =
1018 - L"Network aliases require a user-defined network. Use --network to specify one.\r\nError code: E_INVALIDARG\r\n",
1031 + {.Stderr = FormatErrorMessage(
1032 + L"Network aliases require a user-defined network. Use --network to specify one.", L"E_INVALIDARG"),
1033 .ExitCode = 1});
1034 }
1035
@@ -1075,7 +1089,7 @@ class WSLCE2EContainerRunTests
1089 auto result =
1090 RunWslc(std::format(L"container run --rm --ip {} --name {} {} true", ipAddress, WslcContainerName, DebianImage.NameAndTag()));
1091 result.Verify(
1078 - {.Stderr = std::format(L"{}\r\nError code: E_INVALIDARG\r\n", wsl::shared::Localization::MessageWslcIpRequiresUserDefinedNetwork()),
1092 + {.Stderr = FormatErrorMessage(wsl::shared::Localization::MessageWslcIpRequiresUserDefinedNetwork(), L"E_INVALIDARG"),
1093 .ExitCode = 1});
1094 }
1095
@@ -1086,7 +1100,7 @@ class WSLCE2EContainerRunTests
1100 auto result = RunWslc(std::format(
1101 L"container run --rm --network bridge --ip {} --name {} {} true", ipAddress, WslcContainerName, DebianImage.NameAndTag()));
1102 result.Verify(
1089 - {.Stderr = std::format(L"{}\r\nError code: E_INVALIDARG\r\n", wsl::shared::Localization::MessageWslcIpRequiresUserDefinedNetwork()),
1103 + {.Stderr = FormatErrorMessage(wsl::shared::Localization::MessageWslcIpRequiresUserDefinedNetwork(), L"E_INVALIDARG"),
1104 .ExitCode = 1});
1105 }
1106
@@ -1257,7 +1271,10 @@ with mmap.mmap(fd, 32 * 1024, flags=mmap.MAP_SHARED, prot=mmap.PROT_READ | mmap.
1271 L"container run --rm --name {} --mount type=tmpfs,target=/data --mount type=tmpfs,target=/data/ {} true",
1272 WslcContainerName,
1273 DebianImage.NameAndTag()));
1260 - result.Verify({.Stdout = L"", .Stderr = FormatWslcError(Localization::WSLCCLI_DuplicateMountDestinationError(L"/data")), .ExitCode = 1});
1274 + result.Verify(
1275 + {.Stdout = L"",
1276 + .Stderr = FormatErrorMessage(Localization::WSLCCLI_DuplicateMountDestinationError(L"/data"), L"E_INVALIDARG"),
1277 + .ExitCode = 1});
1278 EnsureContainerDoesNotExist(WslcContainerName);
1279 }
1280
@@ -1358,7 +1375,7 @@ with mmap.mmap(fd, 32 * 1024, flags=mmap.MAP_SHARED, prot=mmap.PROT_READ | mmap.
1375 {
1376 auto result =
1377 RunWslc(std::format(L"container run --rm --stop-timeout -2 --name {} {}", WslcContainerName, DebianImage.NameAndTag()));
1361 - result.Verify({.Stderr = L"Invalid stop timeout value: -2\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1});
1378 + result.Verify({.Stderr = FormatErrorMessage(L"Invalid stop timeout value: -2", L"E_INVALIDARG"), .ExitCode = 1});
1379 EnsureContainerDoesNotExist(WslcContainerName);
1380 }
1381
@@ -1366,7 +1383,7 @@ with mmap.mmap(fd, 32 * 1024, flags=mmap.MAP_SHARED, prot=mmap.PROT_READ | mmap.
1383 {
1384 auto result = RunWslc(std::format(
1385 L"container run --rm --stop-timeout {} --name {} {}", WSLC_STOP_TIMEOUT_DEFAULT, WslcContainerName, DebianImage.NameAndTag()));
1369 - result.Verify({.Stderr = L"Invalid stop timeout value: -2147483648\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1});
1386 + result.Verify({.Stderr = FormatErrorMessage(L"Invalid stop timeout value: -2147483648", L"E_INVALIDARG"), .ExitCode = 1});
1387 EnsureContainerDoesNotExist(WslcContainerName);
1388 }
1389 }
test/windows/wslc/e2e/WSLCE2EContainerStopTests.cpp
+2 -1
@@ -132,7 +132,8 @@ class WSLCE2EContainerStopTests
132
133 auto result = RunWslc(std::format(L"container stop {} -t 0", WslcContainerName));
134 result.Verify(
135 - {.Stderr = std::format(L"Container '{}' not found.\r\nError code: WSLC_E_CONTAINER_NOT_FOUND\r\n", WslcContainerName),
135 + {.Stderr =
136 + FormatErrorMessage(std::format(L"Container '{}' not found.", WslcContainerName), L"WSLC_E_CONTAINER_NOT_FOUND"),
137 .ExitCode = 1});
138 }
139
test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp
+12 -7
@@ -230,7 +230,7 @@ class WSLCE2EGlobalTests
230 result = RunWslc(std::format(L"--session \"{}\" container list", adminName), ElevationType::NonElevated);
231
232 // Should fail with access denied.
233 - result.Verify({.Stderr = L"The requested operation requires elevation. \r\nError code: ERROR_ELEVATION_REQUIRED\r\n", .ExitCode = 1});
233 + result.Verify({.Stderr = FormatErrorMessage(L"The requested operation requires elevation. ", L"ERROR_ELEVATION_REQUIRED"), .ExitCode = 1});
234 }
235
236 WSLC_TEST_METHOD(WSLCE2E_Session_ElevatedCanAccessNonElevatedSession)
@@ -256,11 +256,13 @@ class WSLCE2EGlobalTests
256 auto nonAdminName = GetExpectedDefaultSessionName(false);
257 auto adminName = GetExpectedDefaultSessionName(true);
258 auto result = RunWslc(std::format(L"--session \"{}\" container list", nonAdminName), ElevationType::Elevated);
259 - result.Verify({.Stderr = std::format(L"Session not found: '{}'\r\nError code: WSLC_E_SESSION_NOT_FOUND\r\n", nonAdminName), .ExitCode = 1});
259 + result.Verify(
260 + {.Stderr = FormatErrorMessage(std::format(L"Session not found: '{}'", nonAdminName), L"WSLC_E_SESSION_NOT_FOUND"), .ExitCode = 1});
261
262 // Ensure non-elevated cannot create the elevated session.
263 result = RunWslc(std::format(L"--session \"{}\" container list", adminName), ElevationType::NonElevated);
263 - result.Verify({.Stderr = std::format(L"Session not found: '{}'\r\nError code: WSLC_E_SESSION_NOT_FOUND\r\n", adminName), .ExitCode = 1});
264 + result.Verify(
265 + {.Stderr = FormatErrorMessage(std::format(L"Session not found: '{}'", adminName), L"WSLC_E_SESSION_NOT_FOUND"), .ExitCode = 1});
266 }
267
268 // Regression test for session name squatting vulnerability.
@@ -461,7 +463,7 @@ class WSLCE2EGlobalTests
463
464 // Attempt to terminate the admin session from the non-elevated process and fail.
465 result = RunWslc(std::format(L"--session \"{}\" system session terminate", adminName), ElevationType::NonElevated);
464 - result.Verify({.Stderr = L"The requested operation requires elevation. \r\nError code: ERROR_ELEVATION_REQUIRED\r\n", .ExitCode = 1});
466 + result.Verify({.Stderr = FormatErrorMessage(L"The requested operation requires elevation. ", L"ERROR_ELEVATION_REQUIRED"), .ExitCode = 1});
467
468 // Terminate the non-elevated session from the elevated process.
469 result = RunWslc(std::format(L"--session \"{}\" system session terminate", nonAdminName), ElevationType::Elevated);
@@ -491,7 +493,9 @@ class WSLCE2EGlobalTests
493 // Verify targeting a non-existent session fails.
494 auto result = RunWslc(L"--session INVALID_SESSION_NAME container list");
495 result.Verify(
494 - {.Stdout = L"", .Stderr = L"Session not found: 'INVALID_SESSION_NAME'\r\nError code: WSLC_E_SESSION_NOT_FOUND\r\n", .ExitCode = 1});
496 + {.Stdout = L"",
497 + .Stderr = FormatErrorMessage(L"Session not found: 'INVALID_SESSION_NAME'", L"WSLC_E_SESSION_NOT_FOUND"),
498 + .ExitCode = 1});
499
500 // Verify session list
501 result = RunWslc(L"system session list");
@@ -621,12 +625,13 @@ class WSLCE2EGlobalTests
625
626 {
627 auto result = RunWslc(L"--session not-found system session run echo OK");
624 - result.Verify({.Stderr = L"Session not found: 'not-found'\r\nError code: WSLC_E_SESSION_NOT_FOUND\r\n", .ExitCode = 1});
628 + result.Verify({.Stderr = FormatErrorMessage(L"Session not found: 'not-found'", L"WSLC_E_SESSION_NOT_FOUND"), .ExitCode = 1});
629 }
630
631 {
632 auto result = RunWslc(L"system session run not-found");
629 - result.Verify({.Stdout = L"", .Stderr = L"Failed to launch command not-found. Errno = 2\r\nError code: E_FAIL\r\n", .ExitCode = 1});
633 + result.Verify(
634 + {.Stdout = L"", .Stderr = FormatErrorMessage(L"Failed to launch command not-found. Errno = 2", L"E_FAIL"), .ExitCode = 1});
635 }
636 }
637
test/windows/wslc/e2e/WSLCE2EHelpers.h
-5
@@ -23,11 +23,6 @@ Abstract:
23
24 namespace WSLCE2ETests {
25
26 -inline std::wstring FormatWslcError(const std::wstring& message, std::wstring_view errorCode = L"E_INVALIDARG")
27 -{
28 - return std::format(L"{}\r\nError code: {}\r\n", message, errorCode);
29 -}
30 -
26 // VT sequence constants and helpers for TTY testing.
27 // Sequences are sourced from wsl::windows::common::vt (VTSupport.h).
28 namespace VT {
test/windows/wslc/e2e/WSLCE2EImageBuildTests.cpp
+5 -4
@@ -1205,7 +1205,7 @@ class WSLCE2EImageBuildTests
1205 auto buildResult = RunWslc(std::format(L"build \"{}\"", testRoot.wstring()));
1206 buildResult.Verify(
1207 {.Stderr =
1208 - L"Both Dockerfile and Containerfile found. Use -f to select the file to use\r\nError code: E_INVALIDARG\r\n",
1208 + FormatErrorMessage(L"Both Dockerfile and Containerfile found. Use -f to select the file to use", L"E_INVALIDARG"),
1209 .ExitCode = 1});
1210 }
1211
@@ -1217,7 +1217,8 @@ class WSLCE2EImageBuildTests
1217 auto absolutePath = std::filesystem::absolute(testRoot);
1218 auto buildResult = RunWslc(std::format(L"build \"{}\"", testRoot.wstring()));
1219 buildResult.Verify(
1220 - {.Stderr = std::format(L"No Containerfile or Dockerfile found in '{}'\r\nError code: E_INVALIDARG\r\n", absolutePath.wstring()),
1220 + {.Stderr = FormatErrorMessage(
1221 + std::format(L"No Containerfile or Dockerfile found in '{}'", absolutePath.wstring()), L"E_INVALIDARG"),
1222 .ExitCode = 1});
1223 }
1224
@@ -1237,8 +1238,8 @@ class WSLCE2EImageBuildTests
1238 auto absoluteContainerfilePath = std::filesystem::absolute(containerfilePath);
1239 auto buildResult = RunWslc(std::format(L"build \"{}\"", testRoot.wstring()));
1240 buildResult.Verify(
1240 - {.Stderr = std::format(
1241 - L"Failed to open '{}': Access is denied. \r\nError code: E_ACCESSDENIED\r\n", absoluteContainerfilePath.wstring()),
1241 + {.Stderr = FormatErrorMessage(
1242 + std::format(L"Failed to open '{}': Access is denied. ", absoluteContainerfilePath.wstring()), L"E_ACCESSDENIED"),
1243 .ExitCode = 1});
1244 }
1245
test/windows/wslc/e2e/WSLCE2EImageDeleteTests.cpp
+10 -7
@@ -52,7 +52,8 @@ class WSLCE2EImageDeleteTests
52 WSLC_TEST_METHOD(WSLCE2E_Image_Delete_ImageNotFound)
53 {
54 auto result = RunWslc(std::format(L"image delete {}", InvalidImage.Name));
55 - auto errorMessage = std::format(L"No such image: {}\r\nError code: WSLC_E_IMAGE_NOT_FOUND\r\n", InvalidImage.NameAndTag());
55 + auto errorMessage =
56 + FormatErrorMessage(std::format(L"No such image: {}", InvalidImage.NameAndTag()), L"WSLC_E_IMAGE_NOT_FOUND");
57 result.Verify({.Stdout = L"", .Stderr = errorMessage, .ExitCode = 1});
58 }
59
@@ -99,12 +100,14 @@ class WSLCE2EImageDeleteTests
100 auto imageId = GetHashId(inspectImage.Id);
101
102 auto result = RunWslc(std::format(L"image delete {}", DebianImage.Name));
102 - auto errorMessage = std::format(
103 - L"conflict: unable to remove repository reference \"{}\" (must force) - container {} is using its referenced image "
104 - L"{}\r\nError code: ERROR_SHARING_VIOLATION\r\n",
105 - DebianImage.Name,
106 - containerId,
107 - imageId);
103 + auto errorMessage = FormatErrorMessage(
104 + std::format(
105 + L"conflict: unable to remove repository reference \"{}\" (must force) - container {} is using its referenced "
106 + L"image {}",
107 + DebianImage.Name,
108 + containerId,
109 + imageId),
110 + L"ERROR_SHARING_VIOLATION");
111 result.Verify({.Stdout = L"", .Stderr = errorMessage, .ExitCode = 1});
112 }
113
test/windows/wslc/e2e/WSLCE2EImageSaveTests.cpp
+1 -1
@@ -61,7 +61,7 @@ class WSLCE2EImageSaveTests
61 WSLC_TEST_METHOD(WSLCE2E_Image_Save_ImageNotFound)
62 {
63 const auto result = RunWslc(std::format(L"image save --output \"{}\" {}", SavedArchivePath.wstring(), InvalidImage.NameAndTag()));
64 - result.Verify({.Stdout = L"", .Stderr = L"reference does not exist\r\nError code: WSLC_E_IMAGE_NOT_FOUND\r\n", .ExitCode = 1});
64 + result.Verify({.Stdout = L"", .Stderr = FormatErrorMessage(L"reference does not exist", L"WSLC_E_IMAGE_NOT_FOUND"), .ExitCode = 1});
65 }
66
67 WSLC_TEST_METHOD(WSLCE2E_Image_Save_Success)
test/windows/wslc/e2e/WSLCE2EImageTagTests.cpp
+4 -3
@@ -63,7 +63,8 @@ class WSLCE2EImageTagTests
63 WSLC_TEST_METHOD(WSLCE2E_Image_Tag_SourceImageNotFound)
64 {
65 auto result = RunWslc(std::format(L"image tag {} {}", InvalidImage.NameAndTag(), DebianTaggedImage.NameAndTag()));
66 - auto errorMessage = std::format(L"No such image: {}\r\nError code: WSLC_E_IMAGE_NOT_FOUND\r\n", InvalidImage.NameAndTag());
66 + auto errorMessage =
67 + FormatErrorMessage(std::format(L"No such image: {}", InvalidImage.NameAndTag()), L"WSLC_E_IMAGE_NOT_FOUND");
68 result.Verify({.Stdout = L"", .Stderr = errorMessage, .ExitCode = 1});
69 }
70
@@ -71,8 +72,8 @@ class WSLCE2EImageTagTests
72 {
73 auto imageWithDigest = L"debian-mock:tag@sha256:11111111111111111111111111111111";
74 auto result = RunWslc(std::format(L"image tag {} {}", DebianImage.NameAndTag(), imageWithDigest));
74 - auto errorMessage =
75 - std::format(L"Invalid image tag format: '{}'. Expected format is 'name:tag'\r\nError code: E_INVALIDARG\r\n", imageWithDigest);
75 + auto errorMessage = FormatErrorMessage(
76 + std::format(L"Invalid image tag format: '{}'. Expected format is 'name:tag'", imageWithDigest), L"E_INVALIDARG");
77 result.Verify({.Stdout = L"", .Stderr = errorMessage, .ExitCode = 1});
78 }
79
test/windows/wslc/e2e/WSLCE2ENetworkCreateTests.cpp
+5 -3
@@ -110,7 +110,9 @@ class WSLCE2ENetworkCreateTests
110
111 result = RunWslc(std::format(L"network create --driver bridge {}", TestNetworkName));
112 result.Verify(
113 - {.Stdout = L"", .Stderr = L"Cannot create a file when that file already exists. \r\nError code: ERROR_ALREADY_EXISTS\r\n", .ExitCode = 1});
113 + {.Stdout = L"",
114 + .Stderr = FormatErrorMessage(L"Cannot create a file when that file already exists. ", L"ERROR_ALREADY_EXISTS"),
115 + .ExitCode = 1});
116 }
117
118 WSLC_TEST_METHOD(WSLCE2E_Network_Create_Internal_Success)
@@ -162,7 +164,7 @@ class WSLCE2ENetworkCreateTests
164 auto result = RunWslc(std::format(L"network create --gateway 172.47.0.1 {}", TestNetworkName));
165 result.Verify(
166 {.Stdout = L"",
165 - .Stderr = L"The '--gateway' option requires '--subnet' to also be specified.\r\nError code: E_INVALIDARG\r\n",
167 + .Stderr = FormatErrorMessage(L"The '--gateway' option requires '--subnet' to also be specified.", L"E_INVALIDARG"),
168 .ExitCode = 1});
169
170 VerifyNetworkIsNotListed(TestNetworkName);
@@ -190,7 +192,7 @@ class WSLCE2ENetworkCreateTests
192 auto result = RunWslc(std::format(L"network create --ip-range 172.52.10.0/24 {}", TestNetworkName));
193 result.Verify(
194 {.Stdout = L"",
193 - .Stderr = L"The '--ip-range' option requires '--subnet' to also be specified.\r\nError code: E_INVALIDARG\r\n",
195 + .Stderr = FormatErrorMessage(L"The '--ip-range' option requires '--subnet' to also be specified.", L"E_INVALIDARG"),
196 .ExitCode = 1});
197
198 VerifyNetworkIsNotListed(TestNetworkName);
test/windows/wslc/e2e/WSLCE2ENetworkTests.cpp
+13 -6
@@ -132,7 +132,8 @@ class WSLCE2ENetworkTests
132
133 result = RunWslc(std::format(L"network connect {} {}", TestNetworkName, WslcContainerName));
134 result.Verify(
135 - {.Stderr = std::format(L"Network not found: '{}'\r\nError code: WSLC_E_NETWORK_NOT_FOUND\r\n", TestNetworkName), .ExitCode = 1});
135 + {.Stderr = FormatErrorMessage(std::format(L"Network not found: '{}'", TestNetworkName), L"WSLC_E_NETWORK_NOT_FOUND"),
136 + .ExitCode = 1});
137 }
138
139 WSLC_TEST_METHOD(WSLCE2E_Network_Connect_UnknownContainer)
@@ -142,7 +143,8 @@ class WSLCE2ENetworkTests
143
144 result = RunWslc(std::format(L"network connect {} {}", TestNetworkName, WslcContainerName));
145 result.Verify(
145 - {.Stderr = std::format(L"Container '{}' not found.\r\nError code: WSLC_E_CONTAINER_NOT_FOUND\r\n", WslcContainerName),
146 + {.Stderr =
147 + FormatErrorMessage(std::format(L"Container '{}' not found.", WslcContainerName), L"WSLC_E_CONTAINER_NOT_FOUND"),
148 .ExitCode = 1});
149 }
150
@@ -160,7 +162,8 @@ class WSLCE2ENetworkTests
162 VERIFY_IS_TRUE(result.Stderr.has_value());
163 VerifyPatternMatch(
164 string::WideToMultiByte(result.Stderr.value()),
163 - "*does not support connecting or disconnecting additional networks*Error code: *\r\n");
165 + string::WideToMultiByte(
166 + FormatErrorMessage(L"*does not support connecting or disconnecting additional networks*", L"*")));
167 }
168
169 WSLC_TEST_METHOD(WSLCE2E_Network_Connect_AlreadyConnected_DockerErrorPropagated)
@@ -175,7 +178,9 @@ class WSLCE2ENetworkTests
178 result = RunWslc(std::format(L"network connect {} {}", TestNetworkName, WslcContainerName));
179 VERIFY_ARE_EQUAL(1u, result.ExitCode.value());
180 VERIFY_IS_TRUE(result.Stderr.has_value());
178 - VerifyPatternMatch(string::WideToMultiByte(result.Stderr.value()), "*already exists*Error code: *\r\n");
181 + VerifyPatternMatch(
182 + string::WideToMultiByte(result.Stderr.value()),
183 + string::WideToMultiByte(FormatErrorMessage(L"*already exists*", L"*")));
184 }
185
186 WSLC_TEST_METHOD(WSLCE2E_Network_Connect_WithEndpointFlags_RoundTrips)
@@ -310,7 +315,8 @@ class WSLCE2ENetworkTests
315
316 result = RunWslc(std::format(L"network disconnect {} {}", TestNetworkName, WslcContainerName));
317 result.Verify(
313 - {.Stderr = std::format(L"Network not found: '{}'\r\nError code: WSLC_E_NETWORK_NOT_FOUND\r\n", TestNetworkName), .ExitCode = 1});
318 + {.Stderr = FormatErrorMessage(std::format(L"Network not found: '{}'", TestNetworkName), L"WSLC_E_NETWORK_NOT_FOUND"),
319 + .ExitCode = 1});
320 }
321
322 WSLC_TEST_METHOD(WSLCE2E_Network_Disconnect_UnknownContainer)
@@ -320,7 +326,8 @@ class WSLCE2ENetworkTests
326
327 result = RunWslc(std::format(L"network disconnect {} {}", TestNetworkName, WslcContainerName));
328 result.Verify(
323 - {.Stderr = std::format(L"Container '{}' not found.\r\nError code: WSLC_E_CONTAINER_NOT_FOUND\r\n", WslcContainerName),
329 + {.Stderr =
330 + FormatErrorMessage(std::format(L"Container '{}' not found.", WslcContainerName), L"WSLC_E_CONTAINER_NOT_FOUND"),
331 .ExitCode = 1});
332 }
333
test/windows/wslc/e2e/WSLCE2EPushPullTests.cpp
+4 -3
@@ -126,16 +126,17 @@ class WSLCE2EPushPullTests
126 WSLC_TEST_METHOD(WSLCE2E_Image_Push_NonExistentImage)
127 {
128 auto result = RunWslc(L"push does-not-exist:latest");
129 - auto errorMessage = L"An image does not exist locally with the tag: does-not-exist\r\nError code: E_FAIL\r\n";
129 + auto errorMessage = FormatErrorMessage(L"An image does not exist locally with the tag: does-not-exist", L"E_FAIL");
130 result.Verify({.Stderr = errorMessage, .ExitCode = 1});
131 }
132
133 WSLC_TEST_METHOD(WSLCE2E_Image_Pull_NonExistentImage)
134 {
135 auto result = RunWslc(L"pull does-not-exist:latest");
136 - auto errorMessage =
136 + auto errorMessage = FormatErrorMessage(
137 L"pull access denied for does-not-exist, repository does not exist or may require 'docker login': denied: requested "
138 - L"access to the resource is denied\r\nError code: WSLC_E_IMAGE_NOT_FOUND\r\n";
138 + L"access to the resource is denied",
139 + L"WSLC_E_IMAGE_NOT_FOUND");
140 result.Verify({.Stdout = L"", .Stderr = errorMessage, .ExitCode = 1});
141 }
142
test/windows/wslc/e2e/WSLCE2ESessionEnterTests.cpp
+2 -2
@@ -115,8 +115,8 @@ class WSLCE2ESessionEnterTests
115 // found in '<path>'" message rather than a bare system error.
116 const auto storagePath = std::filesystem::absolute(L"does-not-exist").wstring();
117 result.Verify({
118 - .Stderr = wsl::shared::Localization::MessageWslcSessionStorageNotFound(storagePath) +
119 - L"\r\nError code: ERROR_PATH_NOT_FOUND\r\n",
118 + .Stderr = FormatErrorMessage(
119 + wsl::shared::Localization::MessageWslcSessionStorageNotFound(storagePath), L"ERROR_PATH_NOT_FOUND"),
120 .ExitCode = 1,
121 });
122 }
test/windows/wslc/e2e/WSLCE2EVolumeRemoveTests.cpp
+2 -2
@@ -127,7 +127,7 @@ class WSLCE2EVolumeRemoveTests
127 result = RunWslc(std::format(L"volume remove {}", TestVolumeName));
128 result.Verify(
129 {.Stdout = L"",
130 - .Stderr = std::format(L"Volume '{}' is in use.\r\nError code: ERROR_SHARING_VIOLATION\r\n", TestVolumeName),
130 + .Stderr = FormatErrorMessage(std::format(L"Volume '{}' is in use.", TestVolumeName), L"ERROR_SHARING_VIOLATION"),
131 .ExitCode = 1});
132
133 VerifyVolumeIsListed(TestVolumeName);
@@ -182,7 +182,7 @@ class WSLCE2EVolumeRemoveTests
182 result = RunWslc(std::format(L"volume remove --force {}", TestVolumeName));
183 result.Verify(
184 {.Stdout = L"",
185 - .Stderr = std::format(L"Volume '{}' is in use.\r\nError code: ERROR_SHARING_VIOLATION\r\n", TestVolumeName),
185 + .Stderr = FormatErrorMessage(std::format(L"Volume '{}' is in use.", TestVolumeName), L"ERROR_SHARING_VIOLATION"),
186 .ExitCode = 1});
187
188 VerifyVolumeIsListed(TestVolumeName);