如何在功能测试中模拟inotify相关调用的失败场景?
终端用户视角的inotify应用故障场景功能测试套件
针对你的Linux inotify应用,我整理了一套可直接在终端执行的功能测试套件,重点覆盖你提到的各类inotify系统调用失败场景,全程从终端用户操作出发,不需要修改应用源码。
前置准备
- 确保你的系统安装了
gcc(用于编译hook动态库) - 创建一个临时测试目录:
mkdir -p /tmp/inotify_test && cd /tmp/inotify_test - 备份你的应用配置(如果有),避免测试影响生产环境
1. inotify_init() 调用失败测试
这个场景模拟inotify初始化失败,比如系统文件描述符耗尽、内存不足等情况。
测试步骤:
- 创建一个hook动态库的源码文件
inotify_init_fail.c:
#define _GNU_SOURCE #include <dlfcn.h> #include <sys/inotify.h> #include <errno.h> // 重写inotify_init,强制返回失败并设置错误码 int inotify_init(void) { // 可选错误码:EMFILE(文件描述符过多)、ENOMEM(内存不足) errno = EMFILE; return -1; }
- 编译动态库:
gcc -shared -fPIC inotify_init_fail.c -o libinotify_init_fail.so -ldl
- 运行你的应用并注入hook库:
LD_PRELOAD=./libinotify_init_fail.so ./your_inotify_application
- 预期结果:
- 应用应检测到初始化失败,输出清晰的错误提示(比如
Failed to initialize inotify: Too many open files) - 应用正常退出,无崩溃或无响应情况
- 应用应检测到初始化失败,输出清晰的错误提示(比如
2. inotify_add_watch() 调用失败测试
覆盖权限不足、watch数量超限、目标文件不存在等常见失败场景。
场景A:watch数量超限(ENOSPC)
- 临时降低系统inotify watch上限:
# 先备份原有值 sysctl -n fs.inotify.max_user_watches > /tmp/old_watch_limit # 设置为1,即最多只能创建1个watch sudo sysctl fs.inotify.max_user_watches=1
- 先手动创建一个watch占用配额:
# 执行后保持终端打开,不要关闭 inotifywait -m /tmp > /dev/null &
- 运行你的应用,让它尝试添加新的watch:
./your_inotify_application
- 预期结果:
- 应用应检测到添加watch失败,输出类似
Failed to add watch: No space left on device的错误 - 应用能优雅处理(比如跳过该文件、提示用户或退出),不崩溃
- 应用应检测到添加watch失败,输出类似
- 恢复系统配置:
sudo sysctl fs.inotify.max_user_watches=$(cat /tmp/old_watch_limit) kill %1 # 关闭之前的inotifywait进程
场景B:目标文件权限不足(EACCES)
- 创建一个无权限的测试文件:
sudo touch /tmp/protected_file && sudo chmod 000 /tmp/protected_file
- 配置你的应用监控这个文件,然后运行应用:
./your_inotify_application --watch /tmp/protected_file
- 预期结果:
- 应用应提示权限不足的错误,不会崩溃
- 可选择跳过该文件或终止监控流程
3. inotify_rm_watch() 调用失败测试
模拟移除无效watch描述符的场景。
测试步骤:
- 创建hook库
inotify_rm_watch_fail.c:
#define _GNU_SOURCE #include <dlfcn.h> #include <sys/inotify.h> #include <errno.h> // 重写inotify_rm_watch,强制返回失败 int inotify_rm_watch(int fd, int wd) { errno = EINVAL; // 无效的watch描述符错误 return -1; }
- 编译动态库:
gcc -shared -fPIC inotify_rm_watch_fail.c -o libinotify_rm_watch_fail.so -ldl
- 运行应用并注入hook:
LD_PRELOAD=./libinotify_rm_watch_fail.so ./your_inotify_application
- 预期结果:
- 当应用尝试移除watch时,应检测到错误并输出提示(比如
Failed to remove watch: Invalid argument) - 应用不会崩溃,可继续运行或优雅退出
- 当应用尝试移除watch时,应检测到错误并输出提示(比如
4. read() 调用失败测试
模拟读取inotify事件时的I/O错误、信号中断等场景。
场景A:强制read()返回错误
- 创建hook库
inotify_read_fail.c:
#define _GNU_SOURCE #include <dlfcn.h> #include <unistd.h> #include <errno.h> // 重写read,针对inotify fd返回失败 ssize_t read(int fd, void *buf, size_t count) { // 先获取原始read函数 static ssize_t (*original_read)(int, void*, size_t) = NULL; if (!original_read) { original_read = dlsym(RTLD_NEXT, "read"); } // 强制返回EIO错误(模拟I/O故障) errno = EIO; return -1; }
- 编译动态库:
gcc -shared -fPIC inotify_read_fail.c -o libinotify_read_fail.so -ldl
- 运行应用:
LD_PRELOAD=./libinotify_read_fail.so ./your_inotify_application
- 预期结果:
- 应用应检测到读取事件失败,输出类似
Failed to read inotify events: Input/output error的提示 - 应用可选择重试读取或优雅退出
- 应用应检测到读取事件失败,输出类似
场景B:信号中断read()
- 运行你的应用:
./your_inotify_application & APP_PID=$!
- 向应用发送SIGINT信号中断read调用:
kill -SIGINT $APP_PID
- 预期结果:
- 应用应处理信号中断,不会崩溃
- 可选择恢复监控或正常退出
测试清理
完成所有测试后,清理临时文件和配置:
cd /tmp/inotify_test rm -f *.so *.c rm -rf /tmp/inotify_test
内容的提问来源于stack exchange,提问作者Gill Bates
相关产品推荐
相关产品推荐

