Parallel test execution (#118)

This commit is contained in:
Maurice Heumann
2025-02-04 09:21:55 +01:00
committed by GitHub
11 changed files with 121 additions and 12 deletions

View File

@@ -223,6 +223,11 @@ jobs:
- platform: macOS x86_64
runner: macos-13
steps:
- name: Checkout Source
uses: actions/checkout@v4
with:
submodules: recursive
- name: Download Test Config
uses: pyTooling/download-artifact@v4
with:

5
.gitmodules vendored
View File

@@ -14,4 +14,7 @@
path = deps/zlib
url = https://github.com/madler/zlib.git
branch = develop
ignore = dirty
ignore = dirty
[submodule "deps/gtest-parallel"]
path = deps/gtest-parallel
url = https://github.com/google/gtest-parallel.git

View File

@@ -95,7 +95,10 @@ if(MSVC)
#/LTCG
)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
add_compile_definitions(
_CRT_SECURE_NO_WARNINGS
_CRT_NONSTDC_NO_WARNINGS
)
endif()
##########################################

1
deps/gtest-parallel vendored Submodule

Submodule deps/gtest-parallel added at 96f4f90492

View File

@@ -19,8 +19,13 @@ if(WIN32)
add_dependencies(windows-emulator-test test-sample)
endif()
set(PYTHON3_EXE "python3")
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
set(PYTHON3_EXE "python")
endif()
add_test(NAME windows-emulator-test
COMMAND windows-emulator-test
COMMAND "${PYTHON3_EXE}" "${PROJECT_SOURCE_DIR}/deps/gtest-parallel/gtest_parallel.py" ./windows-emulator-test
WORKING_DIRECTORY "$<TARGET_FILE_DIR:windows-emulator-test>")
momo_targets_set_folder("tests" windows-emulator-test)
momo_targets_set_folder("tests" windows-emulator-test)

View File

@@ -56,6 +56,11 @@ namespace test
settings.application = "c:/test-sample.exe";
settings.emulation_root = get_emulator_root();
settings.port_mappings[28970] = static_cast<uint16_t>(getpid());
settings.path_mappings["C:\\a.txt"] =
std::filesystem::temp_directory_path() / ("emulator-test-file-" + std::to_string(getpid()) + ".txt");
return windows_emulator{std::move(settings), std::move(callbacks)};
}

View File

@@ -121,13 +121,13 @@ namespace
throw std::runtime_error("Unknown socket protocol: " + std::to_string(win_protocol));
}
std::vector<std::byte> convert_to_win_address(const network::address& a)
std::vector<std::byte> convert_to_win_address(const windows_emulator& win_emu, const network::address& a)
{
if (a.is_ipv4())
{
win_sockaddr_in win_addr{};
win_addr.sin_family = translate_host_to_win_address_family(a.get_family());
win_addr.sin_port = htons(a.get_port());
win_addr.sin_port = htons(win_emu.get_emulator_port(a.get_port()));
memcpy(&win_addr.sin_addr, &a.get_in_addr().sin_addr, sizeof(win_addr.sin_addr));
const auto ptr = reinterpret_cast<std::byte*>(&win_addr);
@@ -138,7 +138,7 @@ namespace
{
win_sockaddr_in6 win_addr{};
win_addr.sin6_family = translate_host_to_win_address_family(a.get_family());
win_addr.sin6_port = htons(a.get_port());
win_addr.sin6_port = htons(win_emu.get_emulator_port(a.get_port()));
auto& addr = a.get_in6_addr();
memcpy(&win_addr.sin6_addr, &addr.sin6_addr, sizeof(win_addr.sin6_addr));
@@ -152,7 +152,7 @@ namespace
throw std::runtime_error("Unsupported host address family for conversion: " + std::to_string(a.get_family()));
}
network::address convert_to_host_address(const std::span<const std::byte> data)
network::address convert_to_host_address(const windows_emulator& win_emu, const std::span<const std::byte> data)
{
if (data.size() < sizeof(win_sockaddr))
{
@@ -177,7 +177,7 @@ namespace
memcpy(&win_addr4, data.data(), sizeof(win_addr4));
a.set_ipv4(win_addr4.sin_addr);
a.set_port(ntohs(win_addr4.sin_port));
a.set_port(win_emu.get_host_port(ntohs(win_addr4.sin_port)));
return a;
}
@@ -534,7 +534,7 @@ namespace
return STATUS_BUFFER_TOO_SMALL;
}
const auto addr = convert_to_host_address(std::span(data).subspan(address_offset));
const auto addr = convert_to_host_address(win_emu, std::span(data).subspan(address_offset));
if (bind(*this->s_, &addr.get_addr(), addr.get_size()) == SOCKET_ERROR)
{
@@ -645,7 +645,7 @@ namespace
const auto data_size = std::min(data.size(), static_cast<size_t>(recevied_data));
emu.write_memory(buffer.buf, data.data(), data_size);
const auto win_from = convert_to_win_address(from);
const auto win_from = convert_to_win_address(win_emu, from);
if (receive_info.Address && receive_info.AddressLength)
{
@@ -681,7 +681,7 @@ namespace
auto address_buffer = emu.read_memory(send_info.TdiConnInfo.RemoteAddress,
static_cast<size_t>(send_info.TdiConnInfo.RemoteAddressLength));
const auto target = convert_to_host_address(address_buffer);
const auto target = convert_to_host_address(win_emu, address_buffer);
const auto data = emu.read_memory(buffer.buf, buffer.len);
const auto sent_data =

View File

@@ -19,6 +19,12 @@ class file_system
? win_path
: (this->working_dir_ / win_path);
const auto mapping = this->mappings_.find(full_path);
if (mapping != this->mappings_.end())
{
return mapping->second;
}
#ifdef OS_WINDOWS
if (this->root_.empty())
{
@@ -85,7 +91,13 @@ class file_system
buffer.read(this->working_dir_);
}
void map(windows_path src, std::filesystem::path dest)
{
this->mappings_[std::move(src)] = std::move(dest);
}
private:
std::filesystem::path root_{};
windows_path working_dir_{};
std::unordered_map<windows_path, std::filesystem::path> mappings_{};
};

View File

@@ -838,6 +838,16 @@ windows_emulator::windows_emulator(const emulator_settings& settings, emulator_c
this->file_sys().set_working_directory(settings.application.parent());
}
for (const auto& mapping : settings.path_mappings)
{
this->file_sys().map(mapping.first, mapping.second);
}
for (const auto& mapping : settings.port_mappings)
{
this->map_port(mapping.first, mapping.second);
}
this->verbose_calls = settings.verbose_calls;
this->silent_until_main_ = settings.silent_until_main && !settings.disable_logging;
this->use_relative_time_ = settings.use_relative_time;

View File

@@ -36,6 +36,8 @@ struct emulator_settings
bool disable_logging{false};
bool silent_until_main{false};
bool use_relative_time{false};
std::unordered_map<uint16_t, uint16_t> port_mappings{};
std::unordered_map<windows_path, std::filesystem::path> path_mappings{};
};
enum class apiset_location : uint8_t
@@ -114,6 +116,45 @@ class windows_emulator
this->syscall_hooks_.push_back(std::move(callback));
}
uint16_t get_host_port(const uint16_t emulator_port) const
{
const auto entry = this->port_mappings_.find(emulator_port);
if (entry == this->port_mappings_.end())
{
return emulator_port;
}
return entry->second;
}
uint16_t get_emulator_port(const uint16_t host_port) const
{
for (const auto& mapping : this->port_mappings_)
{
if (mapping.second == host_port)
{
return mapping.first;
}
}
return host_port;
}
void map_port(const uint16_t emulator_port, const uint16_t host_port)
{
if (emulator_port != host_port)
{
this->port_mappings_[emulator_port] = host_port;
return;
}
const auto entry = this->port_mappings_.find(emulator_port);
if (entry != this->port_mappings_.end())
{
this->port_mappings_.erase(entry);
}
}
logger log{};
bool verbose{false};
bool verbose_calls{false};
@@ -161,6 +202,7 @@ class windows_emulator
std::unique_ptr<x64_emulator> emu_{};
std::vector<instruction_hook_callback> syscall_hooks_{};
std::unordered_map<uint16_t, uint16_t> port_mappings_{};
process_context process_;
syscall_dispatcher dispatcher_;

View File

@@ -30,6 +30,8 @@ namespace windows_path_detail
class windows_path
{
public:
friend std::hash<windows_path>;
windows_path() = default;
windows_path(const std::filesystem::path& path)
@@ -234,3 +236,24 @@ class windows_path
}
}
};
template <>
struct std::hash<windows_path>
{
std::size_t operator()(const windows_path& k) const noexcept
{
auto hash = std::hash<bool>()(k.drive_.has_value());
if (k.drive_.has_value())
{
hash ^= std::hash<char>()(*k.drive_);
}
for (const auto& folder : k.folders_)
{
hash ^= std::hash<std::u16string>()(folder);
}
return hash;
}
};