Skip to content

Commit

Permalink
test-runner: Add test-runner
Browse files Browse the repository at this point in the history
Add a test-runner that can be used by CI to execute all test suites and
gather results.

Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
  • Loading branch information
heatd committed Feb 8, 2023
1 parent e033afb commit 0d6dee8
Show file tree
Hide file tree
Showing 9 changed files with 697 additions and 1 deletion.
3 changes: 2 additions & 1 deletion usystem/tests/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ group("tests") {
"kernel_api_tests",
"system_benchmark",
"testsuite",
"kernelbuild-smoketest"
"kernelbuild-smoketest",
"test-runner"
]
}
12 changes: 12 additions & 0 deletions usystem/tests/test-runner/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import("//build/app.gni")

app_executable("test-runner") {
include_dirs = [ "include" ]
package_name = "test-runner"

output_name = "test-runner"

sources = [ "main.cpp", "gtest.cpp", "fsx.cpp", "process.cpp", "kunit.cpp"]

deps = [ "//lib/onyx" ]
}
58 changes: 58 additions & 0 deletions usystem/tests/test-runner/fsx.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2023 Pedro Falcato
* This file is part of Onyx, and is released under the terms of the MIT License
* check LICENSE at the root directory for more information
*
* SPDX-License-Identifier: MIT
*/

#include <err.h>
#include <unistd.h>

#include <filesystem>

#include "include/process.h"
#include "include/test.h"

struct fsx_test : public test
{
std::filesystem::path exec_path_;

fsx_test(std::filesystem::path &&exec, std::string &&name, int timeout_seconds = -1)
: test{std::move(name), timeout_seconds}, exec_path_{std::move(exec)}
{
}

test_result run_test() const override;
};

#define FSX_TEST_DURATION 60

test_result fsx_test::run_test() const
{
if (access(exec_path_.c_str(), X_OK) < 0)
return test_result::skip;

// Make sure fsx-testfile doesn't exist before we start rerunning
unlink("fsx-testfile");

pid_t pid = run_process(exec_path_, {"fsx", "-d", "1m", "fsx-testfile"}, environ);

if (pid < 0)
{
warn("run_process");
return test_result::exec_error;
}

return wait_for_process(pid, "fsx", timeout_seconds_);
}

const fsx_test fsx_t{"/usr/bin/fsx", "fsx", FSX_TEST_DURATION * 2};

const static auto _do = []() {
register_test(&fsx_t);
return 0;
}();

// TODO: Do we want some generic "execute-test-and-look-at-result" logic?
// I tried to be very generic for extensibility's sake
50 changes: 50 additions & 0 deletions usystem/tests/test-runner/gtest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2023 Pedro Falcato
* This file is part of Onyx, and is released under the terms of the MIT License
* check LICENSE at the root directory for more information
*
* SPDX-License-Identifier: MIT
*/

#include <err.h>
#include <unistd.h>

#include <filesystem>

#include "include/process.h"
#include "include/test.h"

struct gtest_test : public test
{
std::filesystem::path exec_path_;
gtest_test(std::filesystem::path &&exec, std::string &&name, int timeout_seconds = -1)
: test{std::move(name), timeout_seconds}, exec_path_{std::move(exec)}
{
}
test_result run_test() const override;
};

const gtest_test gtests[] = {
gtest_test(std::filesystem::path("/usr/bin/kernel_api_tests"), "kernel_api_tests", 30),
gtest_test(std::filesystem::path("/usr/bin/net_tests"), "net_tests", 20)};

test_result gtest_test::run_test() const
{
if (access(exec_path_.c_str(), X_OK) < 0)
return test_result::skip;

pid_t pid = run_process(exec_path_, {name_}, environ);

if (pid < 0)
{
warn("run_process");
return test_result::exec_error;
}

return wait_for_process(pid, name_, timeout_seconds_);
}

const static auto _do = []() {
register_tests(gtests);
return 0;
}();
55 changes: 55 additions & 0 deletions usystem/tests/test-runner/include/process.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2023 Pedro Falcato
* This file is part of Onyx, and is released under the terms of the MIT License
* check LICENSE at the root directory for more information
*
* SPDX-License-Identifier: MIT
*/
#pragma once

#include <err.h>
#include <unistd.h>

#include <cassert>
#include <filesystem>
#include <string>
#include <vector>

#include "test.h"

/**
* @brief Run a process and return its pid
*
* @param exec_path_ Path to the executable
* @param argv Vector of arguments (NOT NULL TERMINATED)
* @param envp envp (NULL-terminated)
* @return -1 on error, pids > 0
*/
pid_t run_process(const std::filesystem::path &exec_path_, const std::vector<std::string> &argv,
char **envp);

/**
* @brief Interpret a wait status into a test result
*
* @param wstatus Wait status
* @param test_name Name of the test (for logging purposes)
* @return A valid test_result value
*/
test_result interpret_wstatus(int wstatus, const std::string &test_name);

/**
* @brief Wait for a process
* Note: May SIGTERM and SIGKILL a process if it times out.
*
* @param pid PID to wait for
* @param test_name Name of the test (for logging purposes)
* @param timeout Timeout in seconds, if set for the test, else -1 (sleeps forever)
* @return A valid test_result value
*/
test_result wait_for_process(pid_t pid, const std::string &test_name, int timeout);

/**
* @brief Set up SIGCHLD handling
*
*/
void setup_sigchld();
65 changes: 65 additions & 0 deletions usystem/tests/test-runner/include/test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2023 Pedro Falcato
* This file is part of Onyx, and is released under the terms of the MIT License
* check LICENSE at the root directory for more information
*
* SPDX-License-Identifier: MIT
*/

#pragma once
#include <string>

enum class test_result
{
ok = 0,
error = 1,
skip = 2,
exec_error
};

/**
* @brief Represents a generic test skeleton
* Various test backends then implement this.
*
*/
struct test
{
std::string name_;
int timeout_seconds_ = -1;

bool dont_re_run = false;

test(std::string &&name, int timeout_seconds)
: name_{std::move(name)}, timeout_seconds_{timeout_seconds}
{
}

void no_rerun()
{
dont_re_run = true;
}

virtual test_result run_test() const = 0;
};

/**
* @brief Register a test
*
* @param t Test to register
*/
void register_test(const test *t);

/**
* @brief Register tests
*
* @tparam Container Container type
* @param c Container to look at and register tests from
*/
template <typename Container>
void register_tests(const Container &c)
{
for (auto &t : c)
{
register_test(&t);
}
}
65 changes: 65 additions & 0 deletions usystem/tests/test-runner/kunit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2023 Pedro Falcato
* This file is part of Onyx, and is released under the terms of the MIT License
* check LICENSE at the root directory for more information
*
* SPDX-License-Identifier: MIT
*/
#include <err.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

#include "include/test.h"

struct kunit_test : public test
{
kunit_test() : test{"kunit", 0}
{
dont_re_run = true;
}

test_result run_test() const override;
};

test_result kunit_test::run_test() const
{
// Get the dmesg
int size = (int) syscall(SYS_syslog, 10, nullptr, -1);
if (size < 0)
err(1, "syslog");

std::string log;
log.resize(size);

if (syscall(SYS_syslog, 2, log.data(), size) < 0)
err(1, "syslog");

// Now look for "kunit: tests done --" and get that line
auto pos = log.find("kunit: tests done --");

if (pos == std::string::npos)
return test_result::skip;

const char *s = log.data() + pos;

unsigned int total = 0;
unsigned int failed = 0;

if (sscanf(s, "kunit: tests done -- %u tests executed, %u", &total, &failed) != 2)
{
warnx("kunit_test: Kernel broke kunit result log format...\n");
return test_result::error;
}

printf("kunit: tests done -- %u tests executed, %u failed\n", total, failed);

return failed != 0 ? test_result::error : test_result::ok;
}

static kunit_test ku;

const static auto _do = []() {
register_test(&ku);
return 0;
}();
Loading

0 comments on commit 0d6dee8

Please sign in to comment.