Linux C轻量级白盒测试方法 (shell + c + signal)

Linux C轻量级的白盒测试方法 (shell + c + signal)

简介

  • 目的:当我们写好一个程序,往往需要测试及调试以保证功能的正确性,有时借助gtest等单元测试工具进行测试,但也可以自己设计一种简单轻量化的白盒测试方法去做程序逻辑的测试或调试。
  • 分析:这其中的关键是将各个触发不同逻辑的参数传入逻辑代码,触发不同的业务执行,观测结果。
  • 设计:shell + c + signal, shell脚本将各个参数(参数列表)接收,由于linux下 pkill -USR1 process_name的信号发送命令不方便携带多参数场景,这里写入文件,并通过信号(用户信号USR1)通知c进程,C进程拿到信号后解析文件(文件内容为参数列表),解析出各个参数即可。之后便可根据各个参数做不同的逻辑测试执行逻辑。

源码

  • 信号发送脚本 send_signal.sh
bash 复制代码
#!/bin/bash

#if [ $# -lt 2 ]; then
if [ $# -lt 1 ]; then
#    echo "使用方法: $0 <id> <string1> [<string2> ...]"
    echo "使用方法: $0 <param1> <param2> [<param3> ...]"
    exit 1
fi

#ID=$1
#echo "ID: $ID"
#shift

# 创建一个文件,用于存储字符串参数
OUTPUT_FILE="./signal_params.txt"
echo -n "" > $OUTPUT_FILE

# 写入每个字符串参数
for param in "$@"
do
    echo "$param" >> $OUTPUT_FILE
done

# 获取目标 C 程序的进程 ID
TARGET_PID=$(pgrep -f signal_handler)

if [ -z "$TARGET_PID" ]; then
    echo "找不到目标程序的进程"
    exit 1
fi

echo "发送信号 SIGUSR1 到进程 ID: $TARGET_PID,参数值: $@"
sync
sleep 0.5

# 发送 SIGUSR1 信号到目标进程
kill -SIGUSR1 $TARGET_PID

echo "已发送信号 SIGUSR1 到进程 ID: $TARGET_PID,参数值: $@"
  • 信号接收c进程 signal_handler.c
c 复制代码
/* signal_handler.c */
#include <stdio.h>
#include <stdint.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define MAX_PARAMS 100
#define MAX_PARAM_LENGTH 256
#define SIGNAL_PARAMS_FILE_PATH "./signal_params.txt"

// 全局变量,用于存储字符串参数
static char *global_params[MAX_PARAMS];
static uint16_t global_params_count = 0;

void SignalHandler(int signal)
{
    FILE *file = fopen(SIGNAL_PARAMS_FILE_PATH, "r");
    if (file == NULL)
    {
        perror("无法打开参数文件");
        return;
    }

    // 清空之前的参数
    for (uint16_t i = 0; i < global_params_count; i++)
    {
        free(global_params[i]);
    }
    global_params_count = 0;

    // 读取每个字符串参数KF
    char buffer[MAX_PARAM_LENGTH];
    while (fgets(buffer, sizeof(buffer), file) != NULL)
    {
        buffer[strcspn(buffer, "\n")] = '\0'; // 移除换行符
        global_params[global_params_count] = strdup(buffer);
        global_params_count++;
        if (global_params_count >= MAX_PARAMS)
        {
            printf("signal count[%d] out of range[%d]\n", global_params_count, MAX_PARAMS);
            break;
        }
    }

    fclose(file);

    // 打印接收到的参数
    printf("信号[%d]处理程序被调用\n", signal);
    printf("接收到的参数个数: %u\n", global_params_count);
    for (uint16_t i = 0; i < global_params_count; i++)
    {
        printf("参数%u: %s\n", i + 1, global_params[i]);
    }
}

static void SignalRegister(void)
{
    // 绑定信号处理程序到 SIGUSR1 信号
    signal(SIGUSR1, SignalHandler);

    // 获取并打印当前进程 ID
    pid_t pid = getpid();
    printf("程序已启动,进程 ID: %d\n", pid);

    // 主循环,等待信号
    while (1)
    {
        pause(); // 等待信号
    }

    // 清理分配的内存
    for (uint16_t i = 0; i < global_params_count; i++)
    {
        free(global_params[i]);
    }

}

int main()
{
    SignalRegister();
    return 0;
}

用法

  • 编译并启动c进程等待信号(这里用用户信号)
bash 复制代码
gcc signal_handler.c -o signal_handler
./signal_handler &
[1] 3508
程序已启动,进程 ID: 3508
  • 脚本接收参数并发送信号和参数
bash 复制代码
chmod +x send_signal.sh
./send_signal.sh 
使用方法: ./send_signal.sh <param1> <param2> [<param3> ...]
  • 需要带参数,效果:
bash 复制代码
./send_signal.sh 1 2 3.14 key value 
发送信号 SIGUSR1 到进程 ID: 3508,参数值: 1 2 3.14 key value
已发送信号 SIGUSR1 到进程 ID: 3508,参数值: 1 2 3.14 key value
信号处理程序被调用: signal 10
接收到的参数个数: 5
参数1: 1
参数2: 2
参数3: 3.14
参数4: key
参数5: value
  • 文件内容 signal_params.txt
bash 复制代码
1
2
3.14
key
value
  • 注 : 后续对参数拿到后的使用略,此为简易方案,效果仅供参考
相关推荐
pofenx11 分钟前
使用nps创建隧道,进行内网穿透
linux·网络·内网穿透·nps
Ronin30512 分钟前
【Linux系统】单例式线程池
linux·服务器·单例模式·线程池·线程安全·死锁
desssq35 分钟前
ubuntu 18.04 泰山派编译报错
linux·运维·ubuntu
Lzc77438 分钟前
Linux的多线程
linux·linux的多线程
清风笑烟语40 分钟前
Ubuntu 24.04 搭建k8s 1.33.4
linux·ubuntu·kubernetes
Dovis(誓平步青云)1 小时前
《Linux 基础指令实战:新手入门的命令行操作核心教程(第一篇)》
linux·运维·服务器
好名字更能让你们记住我1 小时前
MYSQL数据库初阶 之 MYSQL用户管理
linux·数据库·sql·mysql·adb·数据库开发·数据库架构
半桔2 小时前
【网络编程】TCP 服务器并发编程:多进程、线程池与守护进程实践
linux·服务器·网络·c++·tcp/ip
维尔切2 小时前
Shell 脚本编程:函数
linux·运维·自动化
穷人小水滴3 小时前
胖喵必快 (pmbs): btrfs 自动快照工具 (每分钟快照)
linux·rust