From 44100f8852fa7d9ba2a6a7b73ccffdfe5cc82be8 Mon Sep 17 00:00:00 2001 From: CismonX Date: Fri, 28 Mar 2025 16:39:29 +0800 Subject: [PATCH] test: add test harness for filesystem --- tests/Makefile.am | 7 +++ tests/atlocal.in | 5 ++ tests/check_fs.c | 145 +++++++++++++++++++++++++++++++++++++++++++++ tests/testsuite.at | 72 ++++++++++++++++++++++ 4 files changed, 229 insertions(+) create mode 100644 tests/check_fs.c diff --git a/tests/Makefile.am b/tests/Makefile.am index a80c016..39ee403 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -25,6 +25,13 @@ if BOOKMARKFS_UTIL check_hashmap.c endif # BOOKMARKFS_UTIL +if BOOKMARKFS_MOUNT + check_PROGRAMS += check-fs + + check_fs_CPPFLAGS = -I$(top_srcdir)/src + check_fs_SOURCES = check_fs.c +endif # BOOKMARKFS_MOUNT + # Autotest setup AUTOTEST = $(AUTOM4TE) --language=autotest diff --git a/tests/atlocal.in b/tests/atlocal.in index 70c6ba5..2026565 100644 --- a/tests/atlocal.in +++ b/tests/atlocal.in @@ -6,6 +6,11 @@ # this notice are preserved. This file is offered as-is, without any warranty. # +# -- Paths -- +top_builddir="@abs_top_builddir@" +buildsrcdir="$top_builddir/src" + +# -- Features -- @BOOKMARKFS_UTIL_TRUE@ feat_bookmarkfs_util=y @BOOKMARKCTL_TRUE@ feat_bookmarkctl=y @BOOKMARKFS_FSCK_TRUE@ feat_bookmarkfs_fsck=y diff --git a/tests/check_fs.c b/tests/check_fs.c new file mode 100644 index 0000000..4084fd0 --- /dev/null +++ b/tests/check_fs.c @@ -0,0 +1,145 @@ +/** + * bookmarkfs/tests/check_fs.c + * ---- + * + * Copyright (C) 2025 CismonX + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include +#include + +#include "frontend_util.h" + +// Forward declaration start +static int dispatch_subcmds (int, char *[]); +static int subcmd_ismount (int, char *[]); +static int subcmd_sleep (int, char *[]); +// Forward declaration end + +static int +dispatch_subcmds ( + int argc, + char *argv[] +) { + if (--argc < 1) { + log_puts("subcmd not given"); + return -1; + } + char const *cmd = *(++argv); + + int status = -1; + if (0 == strcmp("ismount", cmd)) { + status = subcmd_ismount(argc, argv); + } else if (0 == strcmp("sleep", cmd)) { + status = subcmd_sleep(argc, argv); + } else { + log_printf("bad subcmd '%s'", cmd); + } + return status; +} + +static int +subcmd_ismount ( + int argc, + char *argv[] +) { + if (--argc < 1) { + log_puts("path not given"); + return -1; + } + char const *path = *(++argv); + + int flags = O_RDONLY | O_DIRECTORY; +#ifdef O_PATH + flags |= O_PATH; +#endif + int fd = open(path, flags); + if (fd < 0) { + log_printf("open: %s: %s", path, strerror(errno)); + return -1; + } + int status = -1; + + struct stat stat_buf; + if (0 != fstat(fd, &stat_buf)) { + log_printf("fstat(): %s", strerror(errno)); + goto end; + } + dev_t dev = stat_buf.st_dev; + + if (0 != fstatat(fd, "..", &stat_buf, 0)) { + log_printf("fstatat(): %s", strerror(errno)); + goto end; + } + if (dev != stat_buf.st_dev) { + status = 0; + } + + end: + close(fd); + return status; +} + +/** + * Sleep milliseconds. + * + * This sub-command exists because we cannot portably do so in POSIX shell. + */ +static int +subcmd_sleep ( + int argc, + char *argv[] +) { + if (--argc < 1) { + log_puts("duration not given"); + return -1; + } + char const *duration = *(++argv); + + int millis = atoi(duration); + if (millis <= 0) { + log_printf("bad duration %d", millis); + return -1; + } + struct timespec ts = { + .tv_sec = millis / 1000, + .tv_nsec = (millis % 1000) * 1000000 + }; + return clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); +} + +int +main ( + int argc, + char *argv[] +) { + int status = EXIT_FAILURE; + if (0 != dispatch_subcmds(argc, argv)) { + goto end; + } + status = EXIT_SUCCESS; + + end: + return status; +} diff --git a/tests/testsuite.at b/tests/testsuite.at index 5222be4..3650d8c 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -16,6 +16,14 @@ dnl Repeat string n times. dnl m4_define([ATX_REPEAT], [m4_for([unused_], [1], [$1], , [$2])]) +dnl +dnl ATX_OPT_MODULE(name) +dnl +dnl Expands to a string which can be used for `-o backend=NAME` +dnl or `-o handler=NAME` options of a BookmarkFS program. +dnl +m4_define([ATX_OPT_MODULE], [$buildsrcdir/.libs/$1.so:bookmarkfs_$1]) + dnl dnl ATX_FEAT_VAR(feature) dnl @@ -63,6 +71,16 @@ m4_define([ATX_RUN_REPEAT], [ done ]) +dnl +dnl ATX_RUN_IN_DIR(pathname, script) +dnl +m4_define([ATX_RUN_IN_DIR], [ + atx_pwd=$(pwd) + cd "$1" || exit 1 + $2 + cd "$atx_pwd" +]) + dnl dnl ATX_RUN_ONE(cmd) dnl @@ -100,6 +118,60 @@ m4_define([ATX_CHECK_LIB], [ ]) ]) +dnl +dnl ATX_CHECK_FS(backend, [options], src, target, [prepare], [check]) +dnl +dnl Check for a BookmarkFS filesystem. +dnl +m4_define([ATX_CHECK_FS], [ + ATX_CHECK_SIMPLE([ + ATX_FEAT_PREREQ([bookmarkfs-mount], [backend-$1]) + $5 + "$buildsrcdir/mount.bookmarkfs" -F \ + -o "backend=ATX_OPT_MODULE([backend_$1])" \ + -o "fsname=check-$1,no_sandbox,$2" \ + "$3" "$4" 2>mount.bookmarkfs.stderr & + while ! check-fs ismount "$4"; do + check-fs sleep 100 + if ! jobs %%; then + echo 'fs daemon terminated unexpectedly' + exit 1 + fi + done + $6 + ], [ + umount "$4" + ]) +]) + +dnl +dnl ATX_CHECK_FS_NEW(backend, [options], target, [check]) +dnl +dnl Perform filesystem checks using a new bookmark storage +dnl created with mkfs.bookmarkfs. +dnl +m4_define([ATX_CHECK_FS_NEW], [ + ATX_CHECK_FS([$1], [rw,$2], [bookmarks-$1], [$3], [ + ATX_FEAT_PREREQ([bookmarkfs-mkfs], [backend-$1-write]) + "$buildsrcdir/mkfs.bookmarkfs" \ + -o "backend=ATX_OPT_MODULE([backend_$1]),force" \ + "bookmarks-$1" || exit 1 + mkdir -p "$3" + ], [$4]) +]) + +dnl +dnl ATX_CHECK_FS_NEW_ANY([options], [check]) +dnl +m4_define([ATX_CHECK_FS_NEW_ANY], [ + ATX_CHECK_FS_NEW([firefox], [$1], [mnt.tmp], [ + ATX_RUN_IN_DIR([mnt.tmp/bookmarks/unfiled], [$2]) + ]) + ATX_CHECK_FS_NEW([chromium], [$1], [mnt.tmp], [ + ATX_RUN_IN_DIR([mnt.tmp/bookmarks/Other bookmarks], [$2]) + ]) +]) + dnl -- Helper functions -- AT_TEST_HELPER_FN([rand_u64_hex], , , [