tests+kernel+init: Run tests automatically in a headless way
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
apio 2023-07-21 14:09:37 +02:00
parent bcfee628cb
commit cd6bf745a7
Signed by: apio
GPG Key ID: B8A7D06E42258954
13 changed files with 114 additions and 10 deletions

View File

@ -7,15 +7,15 @@ platform:
os: linux
steps:
- name: build
- name: build-and-test
image: ubuntu
commands:
- apt update
- apt install build-essential cmake ninja-build wget nasm genext2fs -y
- apt install build-essential cmake ninja-build wget nasm genext2fs qemu -y
- wget https://pub.cloudapio.eu/luna/toolchains/ci-toolchain-arm64.tar.gz --quiet
- tar xf ci-toolchain-arm64.tar.gz
- rm ci-toolchain-arm64.tar.gz
- tools/rebuild-iso.sh
- tools/run-tests.sh
trigger:
branch:

View File

@ -7,6 +7,7 @@
#include <os/Directory.h>
#include <os/File.h>
#include <os/Process.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -18,6 +19,18 @@
FILE* g_init_log = nullptr;
// Request a successful exit from the system (for tests)
void sigterm_handler(int)
{
_exit(0);
}
// Request a failure exit from the system (for tests)
void sigquit_handler(int)
{
_exit(1);
}
struct Service
{
String name;
@ -315,11 +328,14 @@ int main()
umask(022);
g_init_log = fopen("/tmp/init.log", "w+");
g_init_log = fopen("/dev/uart0", "w+");
fcntl(fileno(g_init_log), F_SETFD, FD_CLOEXEC);
set_hostname();
if (signal(SIGTERM, sigterm_handler) == SIG_ERR) do_log("[init] failed to register handler for SIGTERM");
if (signal(SIGQUIT, sigquit_handler) == SIG_ERR) do_log("[init] failed to register handler for SIGQUIT");
start_services();
while (1)

View File

@ -56,6 +56,7 @@ set(SOURCES
src/fs/devices/FullDevice.cpp
src/fs/devices/ConsoleDevice.cpp
src/fs/devices/FramebufferDevice.cpp
src/fs/devices/UARTDevice.cpp
src/fs/InitRD.cpp
src/thread/ELF.cpp
)
@ -111,6 +112,10 @@ if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/config.cmake)
include(config.cmake)
endif()
if(BUILD_TESTS)
target_compile_definitions(moon PRIVATE MOON_ENABLE_TESTING_FEATURES)
endif()
target_link_options(moon PRIVATE -lgcc -Wl,--build-id=none -z max-page-size=0x1000 -mcmodel=kernel)
set_target_properties(moon PROPERTIES CXX_STANDARD 20)

View File

@ -35,5 +35,9 @@ namespace CPU
bool register_interrupt(u8 interrupt, void (*handler)(Registers*, void*), void* context);
void sync_interrupts();
#ifdef MOON_ENABLE_TESTING_FEATURES
void magic_exit(int status);
#endif
void pause();
}

View File

@ -417,6 +417,17 @@ namespace CPU
change_pic_masks(pic1_mask, pic2_mask);
CPU::restore_interrupts(val);
}
#ifdef MOON_ENABLE_TESTING_FEATURES
// For tests! Must run QEMU with -device isa-debug-exit,iobase=0xf4,iosize=0x04.
void magic_exit(int status)
{
IO::outl(0xf4,
status ? 0x2 : 0x1); // QEMU exits with (status << 1) | 1. Zero would map to 0b11 (3), non-zero would
// map to 0b101 (5).
__builtin_unreachable();
}
#endif
}
// called by kernel_yield

View File

@ -5,6 +5,7 @@
#include "fs/devices/FramebufferDevice.h"
#include "fs/devices/FullDevice.h"
#include "fs/devices/NullDevice.h"
#include "fs/devices/UARTDevice.h"
#include "fs/devices/ZeroDevice.h"
#include "fs/tmpfs/FileSystem.h"
#include "thread/Thread.h"
@ -69,6 +70,7 @@ namespace DeviceRegistry
FullDevice::create();
ConsoleDevice::create();
FramebufferDevice::create();
UARTDevice::create();
return {};
}

View File

@ -15,6 +15,7 @@ namespace DeviceRegistry
Framebuffer = 3,
Disk = 4,
DiskPartition = 5,
Serial = 6,
};
Result<SharedPtr<Device>> fetch_special_device(u32 major, u32 minor);

View File

@ -0,0 +1,14 @@
#include "fs/devices/UARTDevice.h"
#include "arch/Serial.h"
Result<void> UARTDevice::create()
{
auto device = (SharedPtr<Device>)TRY(make_shared<UARTDevice>());
return DeviceRegistry::register_special_device(DeviceRegistry::Serial, 0, device, 0222);
}
Result<usize> UARTDevice::write(const u8* buf, usize, usize length)
{
Serial::write((const char*)buf, length);
return length;
}

View File

@ -0,0 +1,28 @@
#pragma once
#include "fs/devices/DeviceRegistry.h"
class UARTDevice : public Device
{
public:
// Initializer for DeviceRegistry.
static Result<void> create();
Result<usize> read(u8*, usize, usize) const override
{
return 0;
}
Result<usize> write(const u8*, usize, usize) override;
bool blocking() const override
{
return false;
}
StringView device_path() const override
{
return "uart0";
}
virtual ~UARTDevice() = default;
};

View File

@ -38,9 +38,6 @@ Result<u64> sys_sigaction(Registers*, SyscallArgs args)
if (!MemoryManager::copy_from_user_typed(act, &kact)) return err(EFAULT);
kact.__sa_sigreturn = sigreturn;
kinfoln("sigaction: installing signal handler for signo=%d: handler=%p, sigreturn=%p", signo,
(void*)kact.sa_handler, sigreturn);
current->signal_handlers[signo - 1] = kact;
}

View File

@ -1,5 +1,6 @@
#include "thread/Thread.h"
#include "Log.h"
#include "arch/CPU.h"
#include "memory/MemoryManager.h"
#include "thread/Scheduler.h"
#include <bits/atfile.h>
@ -79,7 +80,11 @@ Result<SharedPtr<VFS::Inode>> Thread::resolve_atfile(int dirfd, const String& pa
[[noreturn]] void Thread::exit_and_signal_parent(int _status)
{
#ifndef MOON_ENABLE_TESTING_FEATURES
if (this->id == 1) fail("the init process exited");
#else
if (this->id == 1) CPU::magic_exit(_status);
#endif
if (is_kernel) state = ThreadState::Dying;
else
{

View File

@ -2,6 +2,8 @@
#include <os/ArgumentParser.h>
#include <os/Directory.h>
#include <os/File.h>
#include <os/Process.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/wait.h>
@ -23,10 +25,16 @@ Result<int> luna_main(int argc, char** argv)
{
auto command = TRY(String::format("%s/%s"_sv, test_dir.chars(), program.chars()));
int status = system(command.chars());
if (WEXITSTATUS(status) != 0) return WEXITSTATUS(status);
if (WEXITSTATUS(status) != 0)
{
os::Process::kill(1, SIGQUIT); // Tell init to report a failed test run.
return WEXITSTATUS(status);
}
}
os::println("All tests passed.");
os::Process::kill(1, SIGTERM); // Tell init to report a successful test run.
return 0;
}

View File

@ -16,14 +16,27 @@ cmake --build $LUNA_BUILD_DIR
rm base/etc/init/*
printf "Name=test\nCommand=/bin/run-tests\nWait=true\n" > base/etc/init/00-tests
printf "Name=test\nCommand=/bin/run-tests\nWait=true\nStandardOutput=/dev/uart0\nStandardError=/dev/uart0\n" > base/etc/init/00-tests
tools/make-iso.sh
set +e
tools/fast-run.sh
tools/fast-run.sh -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none
EXIT_CODE=$?
set -e
rm base/etc/init/00-tests
git checkout base/etc/init/
if [ "$EXIT_CODE" -eq "3" ]
then
exit 0
fi
if [ "$EXIT_CODE" -eq "5" ]
then
exit 1
fi
exit $EXIT_CODE