Use RetryWithTimeout for ManageRejectedWhileLocked lock wait (#41188)

Address PR #41170 feedback from @oneblue: the wait for the distribution to enter the Exporting state was capped at ~10 seconds (100 x 100ms), which can flake on slow machines before the export acquires the lock. Replace the hand-rolled poll loop with wsl::shared::retry::RetryWithTimeout and raise the total timeout to two minutes, matching the retryshared.h convention already used elsewhere in the tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com> Copilot-Session: 6c2f7701-180c-45fc-a1d6-c9ca46be324b

Ben Hillis committed Jul 27, 2026 at 16:32 UTC ad8b78ff37be2ee6a3d5451a5db39e5e9977af87
1 file changed +22 -12
test/windows/UnitTests.cpp
+22 -12
@@ -18,6 +18,7 @@ Abstract:
18 #include "install.h"
19 #include <AclAPI.h>
20 #include <fstream>
21 +#include <sstream>
22 #include <filesystem>
23 #include "wslservice.h"
24 #include "registry.hpp"
@@ -29,6 +30,7 @@ Abstract:
30 #include "Distribution.h"
31 #include "WslCoreConfigInterface.h"
32 #include "CommandLine.h"
33 +#include "retryshared.h"
34
35 #define LXSST_TEST_USERNAME L"kerneltest"
36
@@ -3296,19 +3298,27 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
3298 }
3299 });
3300
3299 - // Wait until the service reports the distribution as Exporting (i.e. the lock is held).
3300 - bool locked = false;
3301 - for (int i = 0; i < 100 && !locked; ++i)
3302 - {
3303 - auto [out, _] = LxsstuLaunchWslAndCaptureOutput(L"--list --verbose");
3304 - locked = (out.find(name) != std::wstring::npos) && (out.find(L"Exporting") != std::wstring::npos);
3305 - if (!locked)
3306 - {
3307 - std::this_thread::sleep_for(std::chrono::milliseconds(100));
3308 - }
3309 - }
3301 + // Wait until the service reports the distribution as Exporting (i.e. the lock is held), retrying for up
3302 + // to two minutes so a slow machine doesn't flake before the export acquires the lock.
3303 + wsl::shared::retry::RetryWithTimeout<void>(
3304 + [&]() {
3305 + auto [out, _] = LxsstuLaunchWslAndCaptureOutput(L"--list --verbose");
3306 + bool locked = false;
3307 + std::wistringstream stream(out);
3308 + for (std::wstring line; std::getline(stream, line);)
3309 + {
3310 + if (line.find(name) != std::wstring::npos && line.find(L"Exporting") != std::wstring::npos)
3311 + {
3312 + locked = true;
3313 + break;
3314 + }
3315 + }
3316
3311 - VERIFY_IS_TRUE(locked);
3317 + THROW_HR_IF(E_ABORT, !locked);
3318 + },
3319 + std::chrono::milliseconds(100),
3320 + std::chrono::minutes(2),
3321 + [] { return wil::ResultFromCaughtException() == E_ABORT; });
3322
3323 // Each VHD-mutating manage operation must be rejected with E_ILLEGAL_STATE_CHANGE while the lock is held.
3324 auto verifyRejected = [&](const std::wstring& command) {