/* test_wifi_connect.c — WiFi 设置页 bug1/bug2/bug4 宿主桩测试(2026-09-15)。
*
* 通过 #include meow_netmgrd.c 直接驱动 static 的 wifi_connect_ex(),绕过 daemon 的
* SO_PEERCRED 系统身份鉴权(宿主 CLI=CALL_OTHER 写级必拒,无法经 IPC 测连接路径)。
* 桩 wpa_cli 由本程序写入临时目录;控制文件(status_mode/list/save_fail_once)决定
* status 序列 / list_networks 原文 / save_config 是否首败,调用日志写入
/log 供断言。
*
* 编译:cc -Wall -Wextra -I../meow_launcherd test_wifi_connect.c -o test_wifi_connect
*/
#define _GNU_SOURCE
#define main meow_netmgrd_main
#include "meow_netmgrd.c"
#undef main
#include
static char g_dir[128];
static int g_pass = 0, g_fail = 0;
static void ck(const char *name, int cond, const char *detail)
{
if (cond) { g_pass++; printf("PASS %s\n", name); }
else { g_fail++; printf("FAIL %s: %s\n", name, detail ? detail : ""); }
fflush(stdout);
}
static void putf(const char *name, const char *fmt, ...)
{
char path[192], body[512];
va_list ap;
va_start(ap, fmt);
vsnprintf(body, sizeof body, fmt, ap);
va_end(ap);
snprintf(path, sizeof path, "%s/%s", g_dir, name);
FILE *f = fopen(path, "w");
if (f) { fputs(body, f); fclose(f); }
}
static int log_has(const char *needle)
{
char path[192], buf[8192];
snprintf(path, sizeof path, "%s/log", g_dir);
FILE *f = fopen(path, "r");
if (!f) return 0;
size_t n = fread(buf, 1, sizeof buf - 1, f);
fclose(f);
buf[n] = 0;
return strstr(buf, needle) != NULL;
}
static void reset_log(void)
{
char path[192];
snprintf(path, sizeof path, "%s/log", g_dir);
FILE *f = fopen(path, "w");
if (f) fclose(f);
}
static void write_stub(void)
{
char path[192];
snprintf(path, sizeof path, "%s/wpa_cli", g_dir);
FILE *f = fopen(path, "w");
if (!f) { fprintf(stderr, "stub open fail\n"); exit(2); }
fputs(
"#!/bin/sh\n"
"D=\"${MN_WIFI_DIR:-/tmp}\"\n"
"echo \"$@\" >> \"$D/log\"\n"
"case \"$1\" in\n"
" status)\n"
" m=$(cat \"$D/status_mode\" 2>/dev/null || echo completed)\n"
" if [ \"$m\" = \"associating\" ]; then\n"
" echo \"wpa_state=ASSOCIATING\"; echo \"ssid=MyWiFi\"\n"
" else\n"
" echo \"wpa_state=COMPLETED\"; echo \"ssid=MyWiFi\"\n"
" echo \"ip_address=10.78.193.50\"; echo \"signal=-45\"\n"
" fi\n"
" ;;\n"
" list_networks)\n"
" if [ -f \"$D/list\" ]; then cat \"$D/list\"\n"
" else printf 'network id / ssid / bssid / flags\\n0\\tMyWiFi\\tany\\t[CURRENT]\\n'\n"
" fi\n"
" ;;\n"
" add_network) echo 1 ;;\n"
" set_network) echo OK ;;\n"
" enable_network) echo OK ;;\n"
" select_network) echo OK ;;\n"
" disconnect) echo OK ;;\n"
" save_config)\n"
" if [ -f \"$D/save_fail_once\" ]; then rm -f \"$D/save_fail_once\"; echo FAIL; else echo OK; fi\n"
" ;;\n"
" set) echo OK ;;\n"
" remove_network) echo OK ;;\n"
" *) echo OK ;;\n"
"esac\n"
"exit 0\n",
f);
fclose(f);
chmod(path, 0755);
}
int main(void)
{
snprintf(g_dir, sizeof g_dir, "/tmp/mnwifi.XXXXXX");
if (!mkdtemp(g_dir)) { fprintf(stderr, "mkdtemp fail\n"); return 2; }
write_stub();
setenv("MN_WIFI_DIR", g_dir, 1);
g_mode_meow = 1;
g_connect_wait_ms = 400;
g_connecth_wait_ms = 400;
{
char p[192];
snprintf(p, sizeof p, "%s/wpa_cli", g_dir);
g_wpa_cli = p;
}
ctl_result_t r;
/* ① 成功:命中既有 id=0 + 带新 psk → 更新凭据,等待 COMPLETED,成功报 ip。 */
putf("status_mode", "completed");
ctl_reset(&r, MEOW_OK);
reset_log();
wifi_connect_ex("MyWiFi,secret", &r, 0);
ck("connect-success code", r.code == MEOW_OK, r.text);
ck("connect-success text ip", strstr(r.text, "已连接") && strstr(r.text, "ip=10.78.193.50"), r.text);
ck("connect-success psk update", log_has("set_network 0 psk"), "");
ck("connect-success enable all", log_has("enable_network all"), "");
/* ② 错误密码/不在范围:status 恒 ASSOCIATING → 超时失败,新建 id 被回收。 */
putf("status_mode", "associating");
reset_log();
ctl_reset(&r, MEOW_OK);
wifi_connect_ex("OtherWiFi", &r, 0);
ck("connect-timeout code", r.code == MEOW_ERR_NODEV, r.text);
ck("connect-timeout text", strstr(r.text, "连接失败") != NULL, r.text);
ck("connect-timeout remove new", log_has("remove_network 1"), "");
/* ③ 中文 SSID \xNN 还原匹配:list_networks 原文转义,输入 UTF-8 名 → 命中 id=0 不新建。 */
putf("status_mode", "completed");
putf("list", "network id / ssid / bssid / flags\n0\t\\xe5\\xa4\\xa9\\xe5\\xa4\\xa9\tany\t[CURRENT]\n");
reset_log();
ctl_reset(&r, MEOW_OK);
wifi_connect_ex("天天", &r, 0);
ck("connect-escape match", r.code == MEOW_OK, r.text);
ck("connect-escape no add", !log_has("add_network"), "");
/* ④ connecth:隐藏网络命中既有 id → 追加 scan_ssid 1。 */
putf("status_mode", "completed");
putf("list", "network id / ssid / bssid / flags\n0\tMyWiFi\tany\t[CURRENT]\n");
reset_log();
ctl_reset(&r, MEOW_OK);
wifi_connect_ex("MyWiFi", &r, 1);
ck("connecth scan_ssid", r.code == MEOW_OK && log_has("set_network 0 scan_ssid 1"), r.text);
/* ⑤ save_config 首败 → set update_config 1 重试 → 持久化成功。 */
putf("status_mode", "completed");
putf("list", "network id / ssid / bssid / flags\n0\tMyWiFi\tany\t[CURRENT]\n");
putf("save_fail_once", "1");
reset_log();
ctl_reset(&r, MEOW_OK);
wifi_connect_ex("MyWiFi", &r, 0);
ck("save-config retry", r.code == MEOW_OK && !strstr(r.text, "记录未持久化"), r.text);
ck("save-config set update_config", log_has("set update_config 1"), "");
printf("==============================\nPASS=%d FAIL=%d\n", g_pass, g_fail);
return g_fail == 0 ? 0 : 1;
}