test: add test harness for filesystem

This commit is contained in:
CismonX 2025-03-28 16:39:29 +08:00
parent 9da346753d
commit 44100f8852
No known key found for this signature in database
GPG key ID: 3094873E29A482FB
4 changed files with 229 additions and 0 deletions

View file

@ -25,6 +25,13 @@ if BOOKMARKFS_UTIL
check_hashmap.c check_hashmap.c
endif # BOOKMARKFS_UTIL 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 setup
AUTOTEST = $(AUTOM4TE) --language=autotest AUTOTEST = $(AUTOM4TE) --language=autotest

View file

@ -6,6 +6,11 @@
# this notice are preserved. This file is offered as-is, without any warranty. # 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 @BOOKMARKFS_UTIL_TRUE@ feat_bookmarkfs_util=y
@BOOKMARKCTL_TRUE@ feat_bookmarkctl=y @BOOKMARKCTL_TRUE@ feat_bookmarkctl=y
@BOOKMARKFS_FSCK_TRUE@ feat_bookmarkfs_fsck=y @BOOKMARKFS_FSCK_TRUE@ feat_bookmarkfs_fsck=y

145
tests/check_fs.c Normal file
View file

@ -0,0 +1,145 @@
/**
* bookmarkfs/tests/check_fs.c
* ----
*
* Copyright (C) 2025 CismonX <admin@cismon.net>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <errno.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
#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;
}

View file

@ -16,6 +16,14 @@ dnl Repeat string n times.
dnl dnl
m4_define([ATX_REPEAT], [m4_for([unused_], [1], [$1], , [$2])]) 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
dnl ATX_FEAT_VAR(feature) dnl ATX_FEAT_VAR(feature)
dnl dnl
@ -63,6 +71,16 @@ m4_define([ATX_RUN_REPEAT], [
done 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
dnl ATX_RUN_ONE(cmd) dnl ATX_RUN_ONE(cmd)
dnl 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 -- dnl -- Helper functions --
AT_TEST_HELPER_FN([rand_u64_hex], , , [ AT_TEST_HELPER_FN([rand_u64_hex], , , [