Add scripts to build a toolchain for running VM tests

This commit is contained in:
2024-05-14 22:09:05 +02:00
parent ad697f1957
commit 00b7c328b4
10 changed files with 688 additions and 15 deletions

View File

@ -1,5 +1,6 @@
#include "elna/tester.hpp"
#include <filesystem>
#include <iostream>
#include <fstream>
#include <algorithm>
@ -51,6 +52,16 @@ namespace elna
return "build/tests";
}
static std::filesystem::path in_root_directory()
{
return "build/root";
}
static std::filesystem::path in_root_directory(const std::filesystem::path& path)
{
return in_root_directory() / path;
}
boost::process::v2::process_stdio get_output_streams(const std::uint8_t stream_number,
boost::asio::readable_pipe& read_pipe)
{
@ -114,9 +125,9 @@ namespace elna
{
const std::filesystem::path test_filename = test_entry.path().filename();
std::filesystem::path test_binary = in_build_directory(test_filename);
std::filesystem::path test_object = test_binary;
std::filesystem::path test_log = test_binary;
std::filesystem::path test_binary = in_root_directory("tests" / test_filename);
std::filesystem::path test_object = in_build_directory(test_filename);
std::filesystem::path test_log = in_build_directory(test_filename);
test_binary.replace_extension();
test_object.replace_extension(".o");
test_log.replace_extension(".log");
@ -183,6 +194,74 @@ namespace elna
{ test_binary.string() });
}
static void cpio_archive(boost::asio::io_context& context)
{
boost::asio::readable_pipe read_pipe{ context };
boost::asio::writable_pipe write_pipe{ context };
std::string output;
boost::asio::dynamic_string_buffer buffer = boost::asio::dynamic_buffer(output);
boost::system::error_code ec;
std::ofstream archive_output{ "build/root.cpio", std::ios::binary };
boost::process::v2::process_stdio process_stdio;
auto current_path = std::filesystem::current_path();
std::filesystem::current_path(in_root_directory());
boost::process::v2::process cpio_child(context, boost::process::search_path("cpio"),
{ "-o", "--format=newc" },
boost::process::v2::process_stdio{ write_pipe, read_pipe, nullptr });
for (const auto& entry : std::filesystem::recursive_directory_iterator("."))
{
auto entry_path = entry.path().string() + "\n";
auto entry_iterator = std::cbegin(entry_path);
std::size_t written{ 0 };
while (entry_iterator != std::cend(entry_path))
{
std::size_t written = write_pipe.write_some(boost::asio::buffer(entry_iterator.base(),
std::distance(entry_iterator, std::cend(entry_path))));
std::advance(entry_iterator, written);
}
}
write_pipe.close();
do
{
std::size_t transferred = read_pipe.read_some(buffer.prepare(512), ec);
if (transferred == 0)
{
break;
}
buffer.commit(transferred);
archive_output.write(boost::asio::buffer_cast<const char *>(buffer.data()), buffer.size());
buffer.consume(transferred);
}
while (ec == boost::system::errc::success);
std::filesystem::current_path(current_path);
}
static void run_vm(boost::asio::io_context& context)
{
std::vector<std::string> arguments = {
"-nographic",
"-M", "virt",
"-bios", "default",
"-kernel", "build/tools/linux-5.15.158/arch/riscv/boot/Image",
"-append", "quiet",
"-initrd", "build/root.cpio"
};
auto process = boost::process::v2::process(context,
boost::process::search_path("qemu-system-riscv32"), arguments);
boost::process::v2::execute(std::move(process));
}
static void create_init()
{
std::filesystem::copy("build/tools/init", in_root_directory());
}
static test_results run_in_path(const std::filesystem::path test_directory)
{
test_results results;
@ -196,14 +275,13 @@ namespace elna
}
test_status result;
std::cout << "Running " << test_entry << std::endl;
std::cout << "Compiling " << test_entry << std::endl;
try
{
build_test(context, test_entry);
}
catch (const boost::process::process_error& exception)
{
test_status::build_failed;
std::cout << exception.what() << std::endl;
}
}
@ -224,15 +302,12 @@ namespace elna
print_result(test_entry, result);
results.add_exit_code(result);
}
for (const auto& expectation_entry : std::filesystem::directory_iterator(test_directory / "expectations"))
{
auto test_entry = test_directory / expectation_entry.path().filename();
test_entry.replace_extension(".eln");
auto result = check_expectation(expectation_entry.path(), in_actual_directory());
std::filesystem::copy(test_directory / "expectations", in_root_directory("expectations"),
std::filesystem::copy_options::recursive);
create_init();
cpio_archive(context);
run_vm(context);
print_result(test_entry, result);
results.add_exit_code(result);
}
return results;
}
@ -250,6 +325,14 @@ int main()
std::filesystem::create_directory(elna::in_build_directory());
std::filesystem::create_directory(elna::in_actual_directory());
std::filesystem::remove_all(elna::in_root_directory());
std::filesystem::create_directory(elna::in_root_directory());
std::filesystem::create_directory(elna::in_root_directory("expectations"));
std::filesystem::create_directory(elna::in_root_directory("tests"));
auto current_environment = boost::this_process::environment();
current_environment["PATH"] += "./build/tools/sysroot/bin";
std::cout << "Run all tests and check the results" << std::endl;
std::filesystem::path test_directory{ "tests" };
const auto results = elna::run_in_path(test_directory);