mirror of
https://github.com/microsoft/WSL.git
synced 2025-07-03 15:23:22 +00:00
266 lines
11 KiB
C++
266 lines
11 KiB
C++
![]() |
/*++
|
||
|
|
||
|
Copyright (c) Microsoft. All rights reserved.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
SimpleTests.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This file contains smoke tests for WSL.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#include "Common.h"
|
||
|
|
||
|
namespace SimpleTests {
|
||
|
class SimpleTests
|
||
|
{
|
||
|
WSL_TEST_CLASS(SimpleTests)
|
||
|
|
||
|
// Initialize the tests
|
||
|
TEST_CLASS_SETUP(TestClassSetup)
|
||
|
{
|
||
|
VERIFY_ARE_EQUAL(LxsstuInitialize(FALSE), TRUE);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
TEST_CLASS_CLEANUP(TestClassCleanup)
|
||
|
{
|
||
|
LxsstuUninitialize(FALSE);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
TEST_METHOD(EchoTest)
|
||
|
{
|
||
|
const std::wstring echoExpected = L"LOW!\n";
|
||
|
auto [output, __] = LxsstuLaunchWslAndCaptureOutput(L"echo LOW!");
|
||
|
VERIFY_ARE_EQUAL(output, echoExpected);
|
||
|
}
|
||
|
|
||
|
TEST_METHOD(WhoamiTest)
|
||
|
{
|
||
|
const std::wstring whoamiExpected = L"root\n";
|
||
|
auto [output, __] = LxsstuLaunchWslAndCaptureOutput(L"-u root whoami");
|
||
|
VERIFY_ARE_EQUAL(output, whoamiExpected);
|
||
|
}
|
||
|
|
||
|
TEST_METHOD(ChangeDirTest)
|
||
|
{
|
||
|
const std::wstring cdExpected = L"/root\n";
|
||
|
auto [output, __] = LxsstuLaunchWslAndCaptureOutput(L"--cd ~ --user root pwd");
|
||
|
VERIFY_ARE_EQUAL(output, cdExpected);
|
||
|
}
|
||
|
|
||
|
TEST_METHOD(Daemonize)
|
||
|
{
|
||
|
WslConfigChange config(LxssGenerateTestConfig({.vmIdleTimeout = 0}));
|
||
|
WslShutdown();
|
||
|
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(L"-- eval \"touch /dev/shm/backgroundmagic; daemonize $(which sleep) 30\""), (DWORD)0);
|
||
|
|
||
|
std::this_thread::sleep_for(std::chrono::seconds(20));
|
||
|
|
||
|
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(L"-- ls /dev/shm/backgroundmagic"), (DWORD)0);
|
||
|
}
|
||
|
|
||
|
static void VerifySparse(wchar_t const* path, bool sparse)
|
||
|
{
|
||
|
DWORD attributes = ::GetFileAttributesW(path);
|
||
|
VERIFY_IS_FALSE(attributes == INVALID_FILE_ATTRIBUTES);
|
||
|
VERIFY_IS_TRUE(WI_IsFlagSet(attributes, FILE_ATTRIBUTE_SPARSE_FILE) == sparse);
|
||
|
}
|
||
|
|
||
|
TEST_METHOD(CheckSparse)
|
||
|
{
|
||
|
WSL2_TEST_ONLY();
|
||
|
|
||
|
WslConfigChange config(LxssGenerateTestConfig({.sparse = true}));
|
||
|
|
||
|
std::filesystem::path tar = std::tmpnam(nullptr);
|
||
|
tar += ".tar";
|
||
|
LogInfo("tar %ls", tar.c_str());
|
||
|
auto cleanupTar = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&] {
|
||
|
try
|
||
|
{
|
||
|
std::filesystem::remove(tar);
|
||
|
}
|
||
|
CATCH_LOG()
|
||
|
});
|
||
|
|
||
|
const std::wstring tempDistro = L"temp_distro";
|
||
|
const std::filesystem::path vhdDir = std::tmpnam(nullptr);
|
||
|
LogInfo("vhdDir %ls", vhdDir.c_str());
|
||
|
VERIFY_IS_TRUE(std::filesystem::create_directory(vhdDir));
|
||
|
auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&] {
|
||
|
try
|
||
|
{
|
||
|
LxsstuLaunchWsl(std::format(L"{} {}", WSL_UNREGISTER_ARG, tempDistro).c_str());
|
||
|
std::filesystem::remove_all(vhdDir);
|
||
|
}
|
||
|
CATCH_LOG()
|
||
|
});
|
||
|
|
||
|
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"{} {} {}", WSL_EXPORT_ARG, LXSS_DISTRO_NAME_TEST, tar.wstring()).c_str()), (DWORD)0);
|
||
|
LxsstuLaunchWsl(std::format(L"{} {}", WSL_UNREGISTER_ARG, tempDistro).c_str());
|
||
|
ValidateOutput(
|
||
|
std::format(L"{} {} {} {}", WSL_IMPORT_ARG, tempDistro, vhdDir.wstring(), tar.wstring()).c_str(),
|
||
|
L"The operation completed successfully. \r\n",
|
||
|
L"wsl: Sparse VHD support is currently disabled due to potential data corruption.\r\n"
|
||
|
L"To force a distribution to use a sparse vhd, please run:\r\n"
|
||
|
L"wsl.exe --manage <DistributionName> --set-sparse --allow-unsafe\r\n",
|
||
|
0);
|
||
|
|
||
|
std::filesystem::path vhdPath = vhdDir / LXSS_VM_MODE_VHD_NAME;
|
||
|
VerifySparse(vhdPath.c_str(), false);
|
||
|
|
||
|
WslShutdown();
|
||
|
|
||
|
// Setting a distro VHD to sparse requires the allow unsafe flag.
|
||
|
ValidateOutput(
|
||
|
std::format(L"{} {} {} {}", WSL_MANAGE_ARG, tempDistro, WSL_MANAGE_ARG_SET_SPARSE_OPTION_LONG, L"true").c_str(),
|
||
|
L"Sparse VHD support is currently disabled due to potential data corruption.\r\n"
|
||
|
L"To force a distribution to use a sparse vhd, please run:\r\n"
|
||
|
L"wsl.exe --manage <DistributionName> --set-sparse --allow-unsafe\r\nError code: Wsl/Service/E_INVALIDARG\r\n",
|
||
|
L"",
|
||
|
-1);
|
||
|
|
||
|
VerifySparse(vhdPath.c_str(), false);
|
||
|
|
||
|
ValidateOutput(
|
||
|
std::format(L"{} {} {} {} {}", WSL_MANAGE_ARG, tempDistro, WSL_MANAGE_ARG_SET_SPARSE_OPTION_LONG, L"true", WSL_MANAGE_ARG_ALLOW_UNSAFE)
|
||
|
.c_str(),
|
||
|
L"The operation completed successfully. \r\n",
|
||
|
L"",
|
||
|
0);
|
||
|
|
||
|
VerifySparse(vhdPath.c_str(), true);
|
||
|
|
||
|
// Disabling sparse on a VHD does not require the allow unsafe flag.
|
||
|
ValidateOutput(
|
||
|
std::format(L"{} {} {} {}", WSL_MANAGE_ARG, tempDistro, WSL_MANAGE_ARG_SET_SPARSE_OPTION_LONG, L"false").c_str(),
|
||
|
L"The operation completed successfully. \r\n",
|
||
|
L"",
|
||
|
0);
|
||
|
|
||
|
VerifySparse(vhdPath.c_str(), false);
|
||
|
}
|
||
|
|
||
|
TEST_METHOD(StringHelpers)
|
||
|
{
|
||
|
std::string string1 = "aaaBBB";
|
||
|
std::string string2 = "aaabbb";
|
||
|
VERIFY_IS_TRUE(wsl::shared::string::IsEqual(string1, string2, true));
|
||
|
VERIFY_IS_FALSE(wsl::shared::string::IsEqual(string1, string2, false));
|
||
|
VERIFY_IS_TRUE(wsl::shared::string::IsEqual(string1.c_str(), string2.c_str(), true));
|
||
|
VERIFY_IS_FALSE(wsl::shared::string::IsEqual(string1.c_str(), string2.c_str(), false));
|
||
|
VERIFY_IS_TRUE(wsl::shared::string::StartsWith(string1, string2.substr(0, 3), true));
|
||
|
VERIFY_IS_FALSE(wsl::shared::string::StartsWith(string1, string2, false));
|
||
|
|
||
|
std::wstring wstring1 = L"aaaBBB";
|
||
|
std::wstring wstring2 = L"aaabbb";
|
||
|
VERIFY_IS_TRUE(wsl::shared::string::IsEqual(wstring1, wstring2, true));
|
||
|
VERIFY_IS_FALSE(wsl::shared::string::IsEqual(wstring1, wstring2, false));
|
||
|
VERIFY_IS_TRUE(wsl::shared::string::IsEqual(wstring1.c_str(), wstring2.c_str(), true));
|
||
|
VERIFY_IS_FALSE(wsl::shared::string::IsEqual(wstring1.c_str(), wstring2.c_str(), false));
|
||
|
VERIFY_IS_TRUE(wsl::shared::string::StartsWith(wstring1, wstring2.substr(0, 3), true));
|
||
|
VERIFY_IS_FALSE(wsl::shared::string::StartsWith(wstring1, wstring2, false));
|
||
|
|
||
|
// Test wsl::shared::string::ParseBool
|
||
|
std::vector<std::pair<LPCSTR, std::optional<bool>>> boolTests = {
|
||
|
{"1", true},
|
||
|
{"0", false},
|
||
|
{"true", true},
|
||
|
{"false", false},
|
||
|
{"True", true},
|
||
|
{"False", false},
|
||
|
{"t", std::nullopt},
|
||
|
{"f", std::nullopt},
|
||
|
{"T", std::nullopt},
|
||
|
{"F", std::nullopt},
|
||
|
{nullptr, std::nullopt},
|
||
|
{"", std::nullopt},
|
||
|
{"2", std::nullopt},
|
||
|
{"tru", std::nullopt},
|
||
|
{"fals", std::nullopt},
|
||
|
};
|
||
|
|
||
|
for (const auto& [input, expected] : boolTests)
|
||
|
{
|
||
|
VERIFY_ARE_EQUAL(expected, wsl::shared::string::ParseBool(input));
|
||
|
|
||
|
std::wstring wideString = wsl::shared::string::MultiByteToWide(input);
|
||
|
VERIFY_ARE_EQUAL(expected, wsl::shared::string::ParseBool(wideString.c_str()));
|
||
|
}
|
||
|
|
||
|
// Test wsl::shared::string::ParseMemoryString
|
||
|
const std::vector<std::pair<LPCSTR, std::optional<uint64_t>>> testCases{
|
||
|
{"0", 0},
|
||
|
{"1", 1},
|
||
|
{" 1", 1},
|
||
|
{"1B", 1},
|
||
|
{"1K", 1024},
|
||
|
{"1KB", 1024},
|
||
|
{"2M", 2 * 1024 * 1024},
|
||
|
{"100MB", 100 * 1024 * 1024},
|
||
|
{"9G", 9 * 1024ULL * 1024ULL * 1024ULL},
|
||
|
{"44GB", 44 * 1024ULL * 1024ULL * 1024ULL},
|
||
|
{"1TB", 1ULL << 40},
|
||
|
{"2T", 2ULL << 40},
|
||
|
{"1 B", std::nullopt},
|
||
|
{nullptr, std::nullopt},
|
||
|
{"", std::nullopt},
|
||
|
{"foo", std::nullopt}};
|
||
|
|
||
|
for (const auto& [input, expected] : testCases)
|
||
|
{
|
||
|
VERIFY_ARE_EQUAL(wsl::shared::string::ParseMemorySize(input), expected);
|
||
|
|
||
|
const auto wideInput = wsl::shared::string::MultiByteToWide(input);
|
||
|
VERIFY_ARE_EQUAL(wsl::shared::string::ParseMemorySize(wideInput.c_str()), expected);
|
||
|
}
|
||
|
|
||
|
// Test wsl::shared::string GUID helpers
|
||
|
const GUID guid = {0x1234567a, 0x1234, 0x5678, {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78}};
|
||
|
const std::string guidString = "{1234567a-1234-5678-1234-567812345678}";
|
||
|
const std::string guidStringNoBraces = "1234567a-1234-5678-1234-567812345678";
|
||
|
const std::vector<std::pair<LPCSTR, std::optional<GUID>>> guidTestCases{
|
||
|
{guidString.c_str(), guid},
|
||
|
{guidStringNoBraces.c_str(), guid},
|
||
|
{nullptr, std::nullopt},
|
||
|
{"", std::nullopt},
|
||
|
{"foo", std::nullopt},
|
||
|
{"1234567G-1234-5678-1234-5678123456789", std::nullopt},
|
||
|
{"{1234567a-1234-5678-1234-567812345678", std::nullopt},
|
||
|
{"{1234567aB-1234-5678-1234-567812345678}", std::nullopt}};
|
||
|
|
||
|
for (const auto& [input, expected] : guidTestCases)
|
||
|
{
|
||
|
VERIFY_ARE_EQUAL(expected, wsl::shared::string::ToGuid(input));
|
||
|
const auto wideInput = wsl::shared::string::MultiByteToWide(input);
|
||
|
VERIFY_ARE_EQUAL(expected, wsl::shared::string::ToGuid(wideInput));
|
||
|
}
|
||
|
|
||
|
VERIFY_ARE_EQUAL(guidString, wsl::shared::string::GuidToString<char>(guid));
|
||
|
VERIFY_ARE_EQUAL(guidString, wsl::shared::string::GuidToString<char>(guid, wsl::shared::string::GuidToStringFlags::AddBraces));
|
||
|
VERIFY_ARE_EQUAL(guidStringNoBraces, wsl::shared::string::GuidToString<char>(guid, wsl::shared::string::GuidToStringFlags::None));
|
||
|
|
||
|
auto upperCaseGuidString = guidStringNoBraces;
|
||
|
std::transform(upperCaseGuidString.begin(), upperCaseGuidString.end(), upperCaseGuidString.begin(), toupper);
|
||
|
VERIFY_ARE_EQUAL(upperCaseGuidString, wsl::shared::string::GuidToString<char>(guid, wsl::shared::string::GuidToStringFlags::Uppercase));
|
||
|
|
||
|
const auto wideGuidString = wsl::shared::string::MultiByteToWide(guidString);
|
||
|
VERIFY_ARE_EQUAL(wideGuidString, wsl::shared::string::GuidToString<wchar_t>(guid));
|
||
|
|
||
|
VERIFY_ARE_EQUAL(wideGuidString, wsl::shared::string::GuidToString<wchar_t>(guid, wsl::shared::string::GuidToStringFlags::AddBraces));
|
||
|
const auto wideGuidStringNoBraces = wsl::shared::string::MultiByteToWide(guidStringNoBraces);
|
||
|
VERIFY_ARE_EQUAL(wideGuidStringNoBraces, wsl::shared::string::GuidToString<wchar_t>(guid, wsl::shared::string::GuidToStringFlags::None));
|
||
|
|
||
|
auto upperCaseGuidStringWide = wideGuidStringNoBraces;
|
||
|
std::transform(upperCaseGuidStringWide.begin(), upperCaseGuidStringWide.end(), upperCaseGuidStringWide.begin(), toupper);
|
||
|
VERIFY_ARE_EQUAL(upperCaseGuidStringWide, wsl::shared::string::GuidToString<wchar_t>(guid, wsl::shared::string::GuidToStringFlags::Uppercase));
|
||
|
}
|
||
|
};
|
||
|
} // namespace SimpleTests
|