tests+kernel+init: Run tests automatically in a headless way
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
bcfee628cb
commit
cd6bf745a7
@ -7,15 +7,15 @@ platform:
|
|||||||
os: linux
|
os: linux
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: build
|
- name: build-and-test
|
||||||
image: ubuntu
|
image: ubuntu
|
||||||
commands:
|
commands:
|
||||||
- apt update
|
- 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
|
- wget https://pub.cloudapio.eu/luna/toolchains/ci-toolchain-arm64.tar.gz --quiet
|
||||||
- tar xf ci-toolchain-arm64.tar.gz
|
- tar xf ci-toolchain-arm64.tar.gz
|
||||||
- rm ci-toolchain-arm64.tar.gz
|
- rm ci-toolchain-arm64.tar.gz
|
||||||
- tools/rebuild-iso.sh
|
- tools/run-tests.sh
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
branch:
|
branch:
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <os/Directory.h>
|
#include <os/Directory.h>
|
||||||
#include <os/File.h>
|
#include <os/File.h>
|
||||||
#include <os/Process.h>
|
#include <os/Process.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -18,6 +19,18 @@
|
|||||||
|
|
||||||
FILE* g_init_log = nullptr;
|
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
|
struct Service
|
||||||
{
|
{
|
||||||
String name;
|
String name;
|
||||||
@ -315,11 +328,14 @@ int main()
|
|||||||
|
|
||||||
umask(022);
|
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);
|
fcntl(fileno(g_init_log), F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
set_hostname();
|
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();
|
start_services();
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
|
@ -56,6 +56,7 @@ set(SOURCES
|
|||||||
src/fs/devices/FullDevice.cpp
|
src/fs/devices/FullDevice.cpp
|
||||||
src/fs/devices/ConsoleDevice.cpp
|
src/fs/devices/ConsoleDevice.cpp
|
||||||
src/fs/devices/FramebufferDevice.cpp
|
src/fs/devices/FramebufferDevice.cpp
|
||||||
|
src/fs/devices/UARTDevice.cpp
|
||||||
src/fs/InitRD.cpp
|
src/fs/InitRD.cpp
|
||||||
src/thread/ELF.cpp
|
src/thread/ELF.cpp
|
||||||
)
|
)
|
||||||
@ -111,6 +112,10 @@ if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/config.cmake)
|
|||||||
include(config.cmake)
|
include(config.cmake)
|
||||||
endif()
|
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)
|
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)
|
set_target_properties(moon PROPERTIES CXX_STANDARD 20)
|
||||||
|
@ -35,5 +35,9 @@ namespace CPU
|
|||||||
bool register_interrupt(u8 interrupt, void (*handler)(Registers*, void*), void* context);
|
bool register_interrupt(u8 interrupt, void (*handler)(Registers*, void*), void* context);
|
||||||
void sync_interrupts();
|
void sync_interrupts();
|
||||||
|
|
||||||
|
#ifdef MOON_ENABLE_TESTING_FEATURES
|
||||||
|
void magic_exit(int status);
|
||||||
|
#endif
|
||||||
|
|
||||||
void pause();
|
void pause();
|
||||||
}
|
}
|
||||||
|
@ -417,6 +417,17 @@ namespace CPU
|
|||||||
change_pic_masks(pic1_mask, pic2_mask);
|
change_pic_masks(pic1_mask, pic2_mask);
|
||||||
CPU::restore_interrupts(val);
|
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
|
// called by kernel_yield
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "fs/devices/FramebufferDevice.h"
|
#include "fs/devices/FramebufferDevice.h"
|
||||||
#include "fs/devices/FullDevice.h"
|
#include "fs/devices/FullDevice.h"
|
||||||
#include "fs/devices/NullDevice.h"
|
#include "fs/devices/NullDevice.h"
|
||||||
|
#include "fs/devices/UARTDevice.h"
|
||||||
#include "fs/devices/ZeroDevice.h"
|
#include "fs/devices/ZeroDevice.h"
|
||||||
#include "fs/tmpfs/FileSystem.h"
|
#include "fs/tmpfs/FileSystem.h"
|
||||||
#include "thread/Thread.h"
|
#include "thread/Thread.h"
|
||||||
@ -69,6 +70,7 @@ namespace DeviceRegistry
|
|||||||
FullDevice::create();
|
FullDevice::create();
|
||||||
ConsoleDevice::create();
|
ConsoleDevice::create();
|
||||||
FramebufferDevice::create();
|
FramebufferDevice::create();
|
||||||
|
UARTDevice::create();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ namespace DeviceRegistry
|
|||||||
Framebuffer = 3,
|
Framebuffer = 3,
|
||||||
Disk = 4,
|
Disk = 4,
|
||||||
DiskPartition = 5,
|
DiskPartition = 5,
|
||||||
|
Serial = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
Result<SharedPtr<Device>> fetch_special_device(u32 major, u32 minor);
|
Result<SharedPtr<Device>> fetch_special_device(u32 major, u32 minor);
|
||||||
|
14
kernel/src/fs/devices/UARTDevice.cpp
Normal file
14
kernel/src/fs/devices/UARTDevice.cpp
Normal 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;
|
||||||
|
}
|
28
kernel/src/fs/devices/UARTDevice.h
Normal file
28
kernel/src/fs/devices/UARTDevice.h
Normal 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;
|
||||||
|
};
|
@ -38,9 +38,6 @@ Result<u64> sys_sigaction(Registers*, SyscallArgs args)
|
|||||||
if (!MemoryManager::copy_from_user_typed(act, &kact)) return err(EFAULT);
|
if (!MemoryManager::copy_from_user_typed(act, &kact)) return err(EFAULT);
|
||||||
kact.__sa_sigreturn = sigreturn;
|
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;
|
current->signal_handlers[signo - 1] = kact;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "thread/Thread.h"
|
#include "thread/Thread.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "arch/CPU.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include <bits/atfile.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)
|
[[noreturn]] void Thread::exit_and_signal_parent(int _status)
|
||||||
{
|
{
|
||||||
|
#ifndef MOON_ENABLE_TESTING_FEATURES
|
||||||
if (this->id == 1) fail("the init process exited");
|
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;
|
if (is_kernel) state = ThreadState::Dying;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
#include <os/ArgumentParser.h>
|
#include <os/ArgumentParser.h>
|
||||||
#include <os/Directory.h>
|
#include <os/Directory.h>
|
||||||
#include <os/File.h>
|
#include <os/File.h>
|
||||||
|
#include <os/Process.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/wait.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()));
|
auto command = TRY(String::format("%s/%s"_sv, test_dir.chars(), program.chars()));
|
||||||
int status = system(command.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::println("All tests passed.");
|
||||||
|
|
||||||
|
os::Process::kill(1, SIGTERM); // Tell init to report a successful test run.
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,27 @@ cmake --build $LUNA_BUILD_DIR
|
|||||||
|
|
||||||
rm base/etc/init/*
|
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
|
tools/make-iso.sh
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
tools/fast-run.sh
|
tools/fast-run.sh -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none
|
||||||
|
EXIT_CODE=$?
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
rm base/etc/init/00-tests
|
rm base/etc/init/00-tests
|
||||||
|
|
||||||
git checkout base/etc/init/
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user