mirror of
https://github.com/microsoft/WSL.git
synced 2026-05-31 16:13:47 -05:00
WSLC is a container runtime built on the Windows Subsystem for Linux, enabling Windows applications to create and manage Linux containers through a native Windows API surface. Key components: - wslc.exe: CLI for managing containers, images, volumes, and networks (build, run, stop, inspect, push/pull from registries) - wslcsession.exe: Per-user Windows service hosting container lifecycle, storage management, and networking - WSLC SDK: C++ and C# client libraries with NuGet packaging for programmatic container management - Container networking: port forwarding, DNS tunneling, virtio networking, and HCN integration - Storage: VHD-backed volumes, virtiofs file sharing, overlayfs layers - GPU passthrough and device host proxy support Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com> Co-authored-by: 1wizkid <richard.fricks@hotmail.com> Co-authored-by: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com> Co-authored-by: beena352 <beenachauhan@microsoft.com> Co-authored-by: Blue <OneBlue@users.noreply.github.com> Co-authored-by: Craig Loewen <crloewen@microsoft.com> Co-authored-by: Darshak Bhatti <47045043+dabhattimsft@users.noreply.github.com> Co-authored-by: David Bennett <dbenne@microsoft.com> Co-authored-by: Feng Wang <wang6922@outlook.com> Co-authored-by: Flor Chacon <14323496+florelis@users.noreply.github.com> Co-authored-by: John Stephens <johnstep@microsoft.com> Co-authored-by: JohnMcPMS <johnmcp@microsoft.com> Co-authored-by: Kevin Vega <40717198+kvega005@users.noreply.github.com> Co-authored-by: Pooja Trivedi <poojatrivedi@gmail.com> Co-authored-by: ramesh-ramn <raman.ramesh@gmail.com> Co-authored-by: Richard Fricks <richfr@microsoft.com> Co-authored-by: yao-msft <50888816+yao-msft@users.noreply.github.com>
219 lines
7.3 KiB
C++
219 lines
7.3 KiB
C++
/*++
|
|
|
|
Copyright (c) Microsoft. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
WSLCCLIEnvVarParserUnitTests.cpp
|
|
|
|
Abstract:
|
|
|
|
This file contains unit tests for WSLC CLI environment variable parsing and validation.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "windows/Common.h"
|
|
#include "WSLCCLITestHelpers.h"
|
|
#include "ContainerModel.h"
|
|
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
|
|
using namespace wsl::windows::wslc;
|
|
|
|
namespace WSLCCLIEnvVarParserUnitTests {
|
|
|
|
class WSLCCLIEnvVarParserUnitTests
|
|
{
|
|
WSLC_TEST_CLASS(WSLCCLIEnvVarParserUnitTests)
|
|
|
|
TEST_METHOD_SETUP(TestMethodSetup)
|
|
{
|
|
EnvTestFile = wsl::windows::common::filesystem::GetTempFilename();
|
|
return true;
|
|
}
|
|
|
|
TEST_METHOD_CLEANUP(TestMethodCleanup)
|
|
{
|
|
DeleteFileW(EnvTestFile.c_str());
|
|
return true;
|
|
}
|
|
|
|
TEST_METHOD(WSLCCLIEnvVarParser_ValidEnvVars)
|
|
{
|
|
const auto parsed = models::EnvironmentVariable::Parse(L"FOO=bar");
|
|
VERIFY_IS_TRUE(parsed.has_value());
|
|
VERIFY_ARE_EQUAL(L"FOO=bar", parsed.value());
|
|
}
|
|
|
|
TEST_METHOD(WSLCCLIEnvVarParser_UsesProcessEnvWhenValueMissing)
|
|
{
|
|
constexpr const auto key = L"WSLC_TEST_ENV_FROM_PROCESS";
|
|
VERIFY_IS_TRUE(SetEnvironmentVariableW(key, L"process_value"));
|
|
|
|
auto cleanup = wil::scope_exit([&] { SetEnvironmentVariableW(key, nullptr); });
|
|
|
|
const auto parsed = models::EnvironmentVariable::Parse(key);
|
|
VERIFY_IS_TRUE(parsed.has_value());
|
|
VERIFY_ARE_EQUAL(L"WSLC_TEST_ENV_FROM_PROCESS=process_value", parsed.value());
|
|
}
|
|
|
|
TEST_METHOD(WSLCCLIEnvVarParser_NulloptForWhitespaceOrUnsetVar)
|
|
{
|
|
const auto whitespaceOnly = models::EnvironmentVariable::Parse(L" \t ");
|
|
VERIFY_IS_FALSE(whitespaceOnly.has_value());
|
|
|
|
SetEnvironmentVariableA("WSLC_TEST_ENV_UNSET", nullptr);
|
|
const auto missingFromProcess = models::EnvironmentVariable::Parse(L"WSLC_TEST_ENV_UNSET");
|
|
VERIFY_IS_FALSE(missingFromProcess.has_value());
|
|
}
|
|
|
|
TEST_METHOD(WSLCCLIEnvVarParser_InvalidKeysThrow)
|
|
{
|
|
auto verifyThrowsWithMessage = [](const std::wstring& input, const std::wstring& expectedSubstring) {
|
|
try
|
|
{
|
|
(void)models::EnvironmentVariable::Parse(input);
|
|
VERIFY_FAIL(L"Expected exception");
|
|
}
|
|
catch (const wil::ResultException& ex)
|
|
{
|
|
VERIFY_ARE_EQUAL(E_INVALIDARG, ex.GetErrorCode());
|
|
|
|
const auto raw = ex.GetFailureInfo().pszMessage;
|
|
std::wstring message = raw ? raw : L"";
|
|
VERIFY_ARE_EQUAL(expectedSubstring, message);
|
|
}
|
|
};
|
|
|
|
verifyThrowsWithMessage(L"=value", L"Environment variable key cannot be empty");
|
|
verifyThrowsWithMessage(L"BAD KEY=value", L"Environment variable key 'BAD KEY' cannot contain whitespace");
|
|
verifyThrowsWithMessage(L"BAD\tKEY=value", L"Environment variable key 'BAD\tKEY' cannot contain whitespace");
|
|
verifyThrowsWithMessage(L"BAD\nKEY=value", L"Environment variable key 'BAD\nKEY' cannot contain whitespace");
|
|
}
|
|
|
|
TEST_METHOD(WSLCCLIEnvVarParser_ParseFileParsesAndSkipsExpectedLines)
|
|
{
|
|
constexpr const auto key = L"WSLC_TEST_ENV_FROM_FILE";
|
|
VERIFY_IS_TRUE(SetEnvironmentVariableW(key, L"file_process_value") == TRUE);
|
|
|
|
auto envCleanup = wil::scope_exit([&] { SetEnvironmentVariableW(key, nullptr); });
|
|
|
|
std::ofstream file(EnvTestFile);
|
|
VERIFY_IS_TRUE(file.is_open());
|
|
file << "# comment\n";
|
|
file << "\n";
|
|
file << "KEY1=VALUE1\n";
|
|
file << " KEY2=VALUE2\n";
|
|
file << "WSLC_TEST_ENV_FROM_FILE\n";
|
|
file << "WSLC_TEST_ENV_DOES_NOT_EXIST\n";
|
|
file.close();
|
|
|
|
const auto parsed = models::EnvironmentVariable::ParseFile(EnvTestFile.wstring());
|
|
|
|
VERIFY_ARE_EQUAL(3U, parsed.size());
|
|
VERIFY_ARE_EQUAL(L"KEY1=VALUE1", parsed[0]);
|
|
VERIFY_ARE_EQUAL(L"KEY2=VALUE2", parsed[1]);
|
|
VERIFY_ARE_EQUAL(L"WSLC_TEST_ENV_FROM_FILE=file_process_value", parsed[2]);
|
|
}
|
|
|
|
TEST_METHOD(WSLCCLIEnvVarParser_ParseFileThrowsWhenMissing)
|
|
{
|
|
try
|
|
{
|
|
(void)models::EnvironmentVariable::ParseFile(L"ENV_FILE_NOT_FOUND");
|
|
VERIFY_FAIL(L"Expected exception");
|
|
}
|
|
catch (const wil::ResultException& ex)
|
|
{
|
|
VERIFY_ARE_EQUAL(E_INVALIDARG, ex.GetErrorCode());
|
|
|
|
const auto raw = ex.GetFailureInfo().pszMessage;
|
|
std::wstring message = raw ? raw : L"";
|
|
VERIFY_ARE_EQUAL(L"Environment file 'ENV_FILE_NOT_FOUND' cannot be opened for reading", message);
|
|
}
|
|
}
|
|
|
|
TEST_METHOD(WSLCCLIEnvVarParser_ExplicitEmptyValueIsValid)
|
|
{
|
|
const auto parsed = models::EnvironmentVariable::Parse(L"FOO=");
|
|
VERIFY_IS_TRUE(parsed.has_value());
|
|
VERIFY_ARE_EQUAL(L"FOO=", parsed.value());
|
|
}
|
|
|
|
TEST_METHOD(WSLCCLIEnvVarParser_MultipleEqualsPreservedInValue)
|
|
{
|
|
const auto parsed = models::EnvironmentVariable::Parse(L"FOO=a=b=c");
|
|
VERIFY_IS_TRUE(parsed.has_value());
|
|
VERIFY_ARE_EQUAL(L"FOO=a=b=c", parsed.value());
|
|
}
|
|
|
|
TEST_METHOD(WSLCCLIEnvVarParser_EmptyInputReturnsNullopt)
|
|
{
|
|
const auto parsed = models::EnvironmentVariable::Parse(L"");
|
|
VERIFY_IS_FALSE(parsed.has_value());
|
|
}
|
|
|
|
TEST_METHOD(WSLCCLIEnvVarParser_UsesProcessEnvWhenValueIsExplicitlyEmpty)
|
|
{
|
|
constexpr const auto key = L"WSLC_TEST_ENV_EMPTY_VALUE";
|
|
VERIFY_IS_TRUE(SetEnvironmentVariableW(key, L""));
|
|
|
|
auto cleanup = wil::scope_exit([&] { SetEnvironmentVariableW(key, nullptr); });
|
|
|
|
const auto parsed = models::EnvironmentVariable::Parse(key);
|
|
VERIFY_IS_TRUE(parsed.has_value());
|
|
VERIFY_ARE_EQUAL(L"WSLC_TEST_ENV_EMPTY_VALUE=", parsed.value());
|
|
}
|
|
|
|
TEST_METHOD(WSLCCLIEnvVarParser_ParseFilePreservesTrailingWhitespaceInValue)
|
|
{
|
|
std::ofstream file(EnvTestFile);
|
|
VERIFY_IS_TRUE(file.is_open());
|
|
file << "KEY=value \n";
|
|
file.close();
|
|
|
|
const auto parsed = models::EnvironmentVariable::ParseFile(EnvTestFile.wstring());
|
|
|
|
VERIFY_ARE_EQUAL(1U, parsed.size());
|
|
VERIFY_ARE_EQUAL(L"KEY=value ", parsed[0]);
|
|
}
|
|
|
|
TEST_METHOD(WSLCCLIEnvVarParser_ParseFileThrowsOnInvalidLine)
|
|
{
|
|
try
|
|
{
|
|
std::ofstream file(EnvTestFile);
|
|
VERIFY_IS_TRUE(file.is_open());
|
|
file << "BAD KEY=value\n";
|
|
file.close();
|
|
|
|
(void)models::EnvironmentVariable::ParseFile(EnvTestFile.wstring());
|
|
VERIFY_FAIL(L"Expected exception");
|
|
}
|
|
catch (const wil::ResultException& ex)
|
|
{
|
|
VERIFY_ARE_EQUAL(E_INVALIDARG, ex.GetErrorCode());
|
|
|
|
const auto raw = ex.GetFailureInfo().pszMessage;
|
|
std::wstring message = raw ? raw : L"";
|
|
VERIFY_ARE_EQUAL(L"Environment variable key 'BAD KEY' cannot contain whitespace", message);
|
|
}
|
|
}
|
|
|
|
TEST_METHOD(WSLCCLIEnvVarParser_ParseFileEmptyFileReturnsEmpty)
|
|
{
|
|
std::ofstream file(EnvTestFile);
|
|
VERIFY_IS_TRUE(file.is_open());
|
|
file.close();
|
|
|
|
const auto parsed = models::EnvironmentVariable::ParseFile(EnvTestFile.wstring());
|
|
VERIFY_ARE_EQUAL(0U, parsed.size());
|
|
}
|
|
|
|
private:
|
|
std::filesystem::path EnvTestFile;
|
|
};
|
|
|
|
} // namespace WSLCCLIEnvVarParserUnitTests
|