Add regression tests

This commit is contained in:
Wang Siyuan 2025-12-26 14:30:59 +00:00 committed by Tate, Hongliang Tian
parent 138401b0ab
commit 4a88b6aa86
6 changed files with 234 additions and 69 deletions

View File

@ -0,0 +1,59 @@
// SPDX-License-Identifier: MPL-2.0
#include "pseudo_file_create.h"
static int readlink_check(int fd, const char *expect_prefix, int check_ino)
{
char path[64];
char buf[256];
struct stat st;
fd_path(fd, path, sizeof(path));
ssize_t len = readlink(path, buf, sizeof(buf) - 1);
if (len < 0)
return -1;
buf[len] = '\0';
size_t prefix_len = strlen(expect_prefix);
if (strncmp(buf, expect_prefix, prefix_len) != 0)
return -1;
if (check_ino) {
const char *ino_p = buf + prefix_len;
char *end = NULL;
unsigned long ino = strtoul(ino_p, &end, 10);
if (end == ino_p || *end != ']' || *(end + 1) != '\0')
return -1;
if (fstat(fd, &st) < 0 || st.st_ino != ino)
return -1;
}
return 0;
}
FN_TEST(pseudo_dentry)
{
TEST_RES(readlink_check(pipe_1[0], "pipe:[", 1), _ret == 0);
TEST_RES(readlink_check(pipe_1[1], "pipe:[", 1), _ret == 0);
TEST_RES(readlink_check(sock[0], "socket:[", 1), _ret == 0);
TEST_RES(readlink_check(sock[1], "socket:[", 1), _ret == 0);
TEST_RES(readlink_check(epoll_fd, "anon_inode:[eventpoll]", 0),
_ret == 0);
TEST_RES(readlink_check(event_fd, "anon_inode:[eventfd]", 0),
_ret == 0);
TEST_RES(readlink_check(timer_fd, "anon_inode:[timerfd]", 0),
_ret == 0);
TEST_RES(readlink_check(signal_fd, "anon_inode:[signalfd]", 0),
_ret == 0);
TEST_RES(readlink_check(inotify_fd, "anon_inode:inotify", 0),
_ret == 0);
TEST_RES(readlink_check(pid_fd, "anon_inode:[pidfd]", 0), _ret == 0);
TEST_RES(readlink_check(mem_fd, "/memfd:test_memfd", 0), _ret == 0);
}
END_TEST()
#include "pseudo_file_cleanup.h"

View File

@ -0,0 +1,21 @@
// SPDX-License-Identifier: MPL-2.0
FN_SETUP(cleanup)
{
CHECK(close(pipe_1[0]));
CHECK(close(pipe_1[1]));
CHECK(close(pipe_2[0]));
CHECK(close(pipe_2[1]));
CHECK(close(sock[0]));
CHECK(close(sock[1]));
CHECK(close(epoll_fd));
CHECK(close(event_fd));
CHECK(close(timer_fd));
CHECK(close(signal_fd));
CHECK(close(inotify_fd));
CHECK(close(pid_fd));
CHECK(close(mem_fd));
CHECK(kill(child, SIGKILL));
CHECK(waitpid(child, NULL, 0));
}
END_SETUP()

View File

@ -0,0 +1,66 @@
// SPDX-License-Identifier: MPL-2.0
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/eventfd.h>
#include <sys/timerfd.h>
#include <sys/signalfd.h>
#include <sys/epoll.h>
#include <sys/inotify.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <signal.h>
#include "../test.h"
int pipe_1[2], pipe_2[2];
int sock[2];
int epoll_fd, event_fd, timer_fd, signal_fd, inotify_fd, pid_fd, mem_fd;
pid_t child;
FN_SETUP(create)
{
CHECK(pipe(pipe_1));
CHECK(pipe(pipe_2));
CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
epoll_fd = CHECK(epoll_create1(EPOLL_CLOEXEC));
event_fd = CHECK(eventfd(0, EFD_CLOEXEC));
timer_fd = CHECK(timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC));
inotify_fd = CHECK(inotify_init1(0));
mem_fd = CHECK(memfd_create("test_memfd", MFD_CLOEXEC));
sigset_t mask;
CHECK(sigemptyset(&mask));
CHECK(sigaddset(&mask, SIGUSR1));
signal_fd = CHECK(signalfd(-1, &mask, SFD_CLOEXEC));
child = CHECK(fork());
if (child == 0) {
pause();
exit(-1);
}
pid_fd = CHECK(syscall(SYS_pidfd_open, child, 0));
}
END_SETUP()
static void __attribute__((unused)) fd_path(int fd, char *buf, size_t buflen)
{
CHECK_WITH(snprintf(buf, buflen, "/proc/self/fd/%d", fd),
_ret > 0 && _ret < buflen);
}
static void __attribute__((unused))
fdinfo_path(int fd, char *buf, size_t buflen)
{
CHECK_WITH(snprintf(buf, buflen, "/proc/self/fdinfo/%d", fd),
_ret > 0 && _ret < buflen);
}

View File

@ -1,28 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/eventfd.h>
#include <sys/timerfd.h>
#include <sys/signalfd.h>
#include <sys/epoll.h>
#include <signal.h>
#include "../test.h"
static void fd_path(int fd, char *buf, size_t buflen)
{
CHECK_WITH(snprintf(buf, buflen, "/proc/self/fd/%d", fd),
_ret > 0 && _ret < buflen);
}
#include "pseudo_file_create.h"
static int get_mode(int fd)
{
@ -46,29 +24,22 @@ static int set_mode(int fd, int mode)
FN_TEST(pipe_ends_share_inode)
{
int pipe1[2], pipe2[2];
TEST_SUCC(pipe(pipe1));
TEST_SUCC(pipe(pipe2));
TEST_RES(get_mode(pipe_1[0]), _ret == 0600);
TEST_RES(get_mode(pipe_1[1]), _ret == 0600);
TEST_RES(get_mode(pipe_2[0]), _ret == 0600);
TEST_RES(get_mode(pipe_2[1]), _ret == 0600);
TEST_RES(get_mode(pipe1[0]), _ret == 0600);
TEST_RES(get_mode(pipe1[1]), _ret == 0600);
TEST_RES(get_mode(pipe2[0]), _ret == 0600);
TEST_RES(get_mode(pipe2[1]), _ret == 0600);
TEST_SUCC(set_mode(pipe_1[0], 0000));
TEST_SUCC(set_mode(pipe1[0], 0000));
TEST_RES(get_mode(pipe1[0]), _ret == 0000);
TEST_RES(get_mode(pipe1[1]), _ret == 0000);
TEST_RES(get_mode(pipe2[0]), _ret == 0600);
TEST_RES(get_mode(pipe2[1]), _ret == 0600);
TEST_RES(get_mode(pipe_1[0]), _ret == 0000);
TEST_RES(get_mode(pipe_1[1]), _ret == 0000);
TEST_RES(get_mode(pipe_2[0]), _ret == 0600);
TEST_RES(get_mode(pipe_2[1]), _ret == 0600);
}
END_TEST()
FN_TEST(sockets_do_not_share_inode)
{
int sock[2];
TEST_SUCC(socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
TEST_RES(get_mode(sock[0]), _ret == 0777);
TEST_RES(get_mode(sock[1]), _ret == 0777);
@ -81,37 +52,23 @@ END_TEST()
FN_TEST(anon_inodefs_share_inode)
{
int fd;
struct fd_mode {
int fd;
mode_t modes[2];
};
// eventfd
fd = TEST_SUCC(eventfd(0, EFD_CLOEXEC));
TEST_RES(get_mode(fd), _ret == 0600);
TEST_SUCC(set_mode(fd, 0000));
TEST_RES(get_mode(fd), _ret == 0000);
TEST_SUCC(close(fd));
struct fd_mode fds[] = {
{ epoll_fd, { 0600, 0000 } }, { event_fd, { 0000, 0111 } },
{ timer_fd, { 0111, 0222 } }, { signal_fd, { 0222, 0333 } },
{ inotify_fd, { 0333, 0444 } }, { pid_fd, { 0444, 0600 } },
};
// timerfd
fd = TEST_SUCC(timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC));
TEST_RES(get_mode(fd), _ret == 0000);
TEST_SUCC(set_mode(fd, 0111));
TEST_RES(get_mode(fd), _ret == 0111);
TEST_SUCC(close(fd));
// signalfd
sigset_t mask;
TEST_SUCC(sigemptyset(&mask));
TEST_SUCC(sigaddset(&mask, SIGUSR1));
fd = TEST_SUCC(signalfd(-1, &mask, SFD_CLOEXEC));
TEST_RES(get_mode(fd), _ret == 0111);
TEST_SUCC(set_mode(fd, 0222));
TEST_RES(get_mode(fd), _ret == 0222);
TEST_SUCC(close(fd));
// epollfd
fd = TEST_SUCC(epoll_create1(EPOLL_CLOEXEC));
TEST_RES(get_mode(fd), _ret == 0222);
TEST_SUCC(set_mode(fd, 0600));
TEST_RES(get_mode(fd), _ret == 0600);
TEST_SUCC(close(fd));
for (size_t i = 0; i < sizeof(fds) / sizeof(fds[0]); i++) {
TEST_RES(get_mode(fds[i].fd), _ret == fds[i].modes[0]);
TEST_SUCC(set_mode(fds[i].fd, fds[i].modes[1]));
TEST_RES(get_mode(fds[i].fd), _ret == fds[i].modes[1]);
}
}
END_TEST()
#include "pseudo_file_cleanup.h"

View File

@ -0,0 +1,60 @@
// SPDX-License-Identifier: MPL-2.0
#include "pseudo_file_create.h"
static int read_fdinfo_mnt_id(int fd)
{
char path[64], line[256];
FILE *f;
fdinfo_path(fd, path, sizeof(path));
f = fopen(path, "r");
if (!f)
return -1;
int mnt_id = -1;
while (fgets(line, sizeof(line), f)) {
if (CHECK(sscanf(line, "mnt_id:\t%d", &mnt_id)) == 1)
break;
}
CHECK(fclose(f));
return mnt_id;
}
FN_TEST(pseudo_mount)
{
int anon[] = { epoll_fd, event_fd, timer_fd,
signal_fd, inotify_fd, pid_fd };
struct fd_group {
int *fds;
int nr;
int mnt_id;
};
struct fd_group groups[] = {
{ pipe_1, 2, -1 },
{ sock, 2, -1 },
{ anon, 6, -1 },
{ &mem_fd, 1, -1 },
};
for (int i = 0; i < 4; i++) {
int base = TEST_SUCC(read_fdinfo_mnt_id(groups[i].fds[0]));
for (int j = 1; j < groups[i].nr; j++) {
TEST_RES(read_fdinfo_mnt_id(groups[i].fds[j]),
_ret == base);
}
groups[i].mnt_id = base;
}
for (int i = 0; i < 4; i++) {
for (int j = i + 1; j < 4; j++) {
TEST_RES(0, groups[i].mnt_id != groups[j].mnt_id);
}
}
}
END_TEST()
#include "pseudo_file_cleanup.h"

View File

@ -51,7 +51,9 @@ process/pidfd
process/wait4
procfs/dentry_cache
procfs/pid_mem
pseudofs/pseudo_dentry
pseudofs/pseudo_inode
pseudofs/pseudo_mount
pseudofs/memfd_access_err
pthread/pthread_test
pty/close_pty