Repository: microsoft/terminal
File: src/host/ft_host/InitTests.cpp (C++)

Code before:
        // Replace CRT handles
        // These need to be reopened as read/write or they can affect some of the tests.
        //
        // std_out and std_in need to be closed when tests are finished, this is handled by the wil::scope_exit at the
        // top of this file.
        auto err = 0;
        err = freopen_s(&std_out, "CONOUT$", "w+", stdout);
        VERIFY_ARE_EQUAL(0, err);
        err = freopen_s(&std_in, "CONIN$", "r+", stdin);
        VERIFY_ARE_EQUAL(0, err);

        // Now, try to get at the console we've set up. It's possible 1s wasn't long enough. If that was, we'll try again.

        const auto hOut = GetStdOutputHandle();
        VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle.");

        CONSOLE_SCREEN_BUFFER_INFOEX csbiexBefore = { 0 };
        csbiexBefore.cbSize = sizeof(csbiexBefore);
        auto succeeded = GetConsoleScreenBufferInfoEx(hOut, &csbiexBefore);
        if (!succeeded)
        {
            auto gle = GetLastError();
            VERIFY_ARE_EQUAL(6u, gle, L"If we fail to set up the console, GetLastError should return 6 here.");

            // Sleep with a backoff, to give us longer to try next time.
            Sleep(1000 * (1 + tries));
        }
        else
        {
            Log::Comment(NoThrowString().Format(L"Succeeded on try #%d", tries));
            break;
        }
    };

    VERIFY_IS_LESS_THAN(tries, 10, L"Make sure we set up the new console in time");

    return true;
}

MODULE_CLEANUP(ModuleCleanup)
{
    v2ModeHelper.reset();
    return true;
}


Review comment (suggestion):
As far as I can tell, and really really don't quote me on this, but as far as I can tell, `Sleep` and all other "waitable" functions are all based on `KiCheckWaitNext` which uses [`QueryInterruptTimePrecise`](https://learn.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryinterrupttimeprecise) for calls like `Sleep` and [`QueryUnbiasedInterruptTime`](https://learn.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryunbiasedinterrupttime) for APIs like `WaitForSingleObject`.

The difference between the `Query*Time` APIs that have unbiased in their name is:
> The unbiased interrupt-time count does not include time the system spends in sleep or hibernation.

In other words, as far as I can tell, `Sleep` sleeps in "real time" and not in "run time", so if our CIs, which probably run on some very cheap spot instances, get suspended quite often, `Sleep` will effectively be skipped every time, without the OS and the apps on it really progressing at all.

I would thus try and fix it by calling this instead:
```cpp
WaitForSingleObject(GetCurrentThread(), 1000);
```

Code after:
        // Replace CRT handles
        // These need to be reopened as read/write or they can affect some of the tests.
        //
        // std_out and std_in need to be closed when tests are finished, this is handled by the wil::scope_exit at the
        // top of this file.
        auto err = 0;
        err = freopen_s(&std_out, "CONOUT$", "w+", stdout);
        VERIFY_ARE_EQUAL(0, err);
        err = freopen_s(&std_in, "CONIN$", "r+", stdin);
        VERIFY_ARE_EQUAL(0, err);

        // Now, try to get at the console we've set up. It's possible 1s wasn't long enough. If that was, we'll try again.

        const auto hOut = GetStdOutputHandle();
        VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle.");

        CONSOLE_SCREEN_BUFFER_INFOEX csbiexBefore = { 0 };
        csbiexBefore.cbSize = sizeof(csbiexBefore);
        auto succeeded = GetConsoleScreenBufferInfoEx(hOut, &csbiexBefore);
        if (!succeeded)
        {
            const auto gle = GetLastError();
            VERIFY_ARE_EQUAL(6u, gle, L"If we fail to set up the console, GetLastError should return 6 here.");

            // Sleep with a backoff, to give us longer to try next time.
            WaitForSingleObject(GetCurrentThread(), delay);
        }
        else
        {
            Log::Comment(NoThrowString().Format(L"Succeeded on try #%d", tries));
            break;
        }
    };

    VERIFY_IS_LESS_THAN(delay, 30000u, L"Make sure we set up the new console in time");

    return true;
}

MODULE_CLEANUP(ModuleCleanup)
{
    v2ModeHelper.reset();
    return true;
}