Files
MeowOS-For-R3P2/patch_v2/sdk/test_notify_integration.c

225 lines
10 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* test_notify_integration.c — 宿主集成测试:meow_notify_send/cancel 全链路(任务 #5)。
*
* 直接把 meow_ui_notify.c + meow_notify_ipc.c 编进来,仅 stub 两个 SDK 能力
* (meow_log 空实现 / meow_ui_time_ms 单调毫秒),用本地 AF_UNIX stub socket 回环:
*
* S1 send(general,timeout=0) → 返回本地 id(1),stub 回 nid=101,active_count=1;
* S2 send(media) → media=1、category=media(经 stub 捕获帧校验);
* S3 同类型再发(未满配额)→ 返回本地 id(3);
* S4 cancel(本地id=1) → 返回 1,stub 收到 MSG_NOTIFY_DISMISS(负载 nid=101);
* S5 配额满(每类型4)后发第 5 条 → 丢最旧:该 5 条 send 的 replaces_id == 被丢最旧的 nid;
* S6 无 launcher(connect 失败)→ send 仍返回本地 id(>0)、不崩;cancel 也静默不崩。
*
* 编译(宿主 gcc):
* gcc -o test_notify_integration test_notify_integration.c \
* meow_ui_notify.c meow_notify_ipc.c -I. -I../meow_launcherd -lpthread
*/
#include "meow_ui.h"
#include "meow_notify_ipc.h"
#include "meow_ipc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <pthread.h>
/* ---- stub SDK 依赖(避免链整库) ---- */
void meow_log(meow_log_level lvl, const char *fmt, ...) { (void)lvl; (void)fmt; }
uint64_t meow_ui_time_ms(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
}
/* ---- stub server 捕获(每次连接一帧) ---- */
#define MAXCAP 16
typedef struct { int type; m_notify_t n; m_notify_progress_t prog; uint32_t dismiss_id; uint32_t nid; } srec_t;
static srec_t g_rec[MAXCAP];
static int g_nrec = 0;
static int g_stop = 0;
static int g_listen_fd = -1;
static pthread_mutex_t g_mu = PTHREAD_MUTEX_INITIALIZER;
static void *server(void *arg)
{
(void)arg;
while (!g_stop) {
int c = accept(g_listen_fd, NULL, NULL);
if (c < 0) {
if (errno == EAGAIN && g_stop) break; /* 非阻塞:listener 被关闭 */
if (errno == EBADF) break;
usleep(1000);
continue;
}
uint8_t hdr[MEOW_IPC_HDR_LEN];
size_t off = 0;
while (off < sizeof hdr) { ssize_t r = read(c, hdr + off, sizeof hdr - off); if (r <= 0) break; off += (size_t)r; }
if (off < sizeof hdr) { close(c); continue; }
uint32_t type, len, req_id;
memcpy(&req_id, hdr + 8, 4);
memcpy(&len, hdr + 12, 4);
memcpy(&type, hdr + 6, 2);
if (len > MEOW_IPC_MAX) { close(c); continue; }
uint8_t pay[MEOW_IPC_MAX];
off = 0;
while (off < len) { ssize_t r = read(c, pay + off, len - off); if (r <= 0) break; off += (size_t)r; }
pthread_mutex_lock(&g_mu);
int idx = g_nrec < MAXCAP ? g_nrec++ : (MAXCAP - 1);
memset(&g_rec[idx], 0, sizeof g_rec[idx]);
g_rec[idx].type = (int)type;
if (type == MSG_NOTIFY && len >= sizeof(m_notify_t)) memcpy(&g_rec[idx].n, pay, sizeof(m_notify_t));
if (type == MSG_NOTIFY_PROGRESS && len >= sizeof(m_notify_progress_t)) memcpy(&g_rec[idx].prog, pay, sizeof(m_notify_progress_t));
if (type == MSG_NOTIFY_DISMISS && len >= 4) memcpy(&g_rec[idx].dismiss_id, pay, 4);
/* 分配 nid = 100 + NOTIFY 序号 */
uint32_t seq = 0;
for (int i = 0; i <= idx; i++) if (g_rec[i].type == MSG_NOTIFY) seq++;
g_rec[idx].nid = (type == MSG_NOTIFY) ? (100 + seq) : 0;
uint32_t ack_nid = g_rec[idx].nid;
pthread_mutex_unlock(&g_mu);
if (type == MSG_NOTIFY || type == MSG_NOTIFY_DISMISS || type == MSG_NOTIFY_PROGRESS) {
m_ack_t a; memset(&a, 0, sizeof a); a.code = MEOW_OK; a.status = ack_nid;
uint8_t rhdr[MEOW_IPC_HDR_LEN];
uint32_t mag = MEOW_IPC_MAGIC; uint16_t ver = MEOW_IPC_VERSION, t = (uint16_t)
(type == MSG_NOTIFY ? MSG_NOTIFY_ACK : MSG_ACK); uint32_t rl = sizeof a;
memcpy(rhdr+0,&mag,4); memcpy(rhdr+4,&ver,2); memcpy(rhdr+6,&t,2); memcpy(rhdr+8,&req_id,4); memcpy(rhdr+12,&rl,4);
size_t w0 = 0; while (w0 < sizeof rhdr) { ssize_t w = write(c, rhdr+w0, sizeof rhdr-w0); if (w<=0) break; w0 += (size_t)w; }
size_t w1 = 0; while (w1 < rl) { ssize_t w = write(c, (uint8_t*)&a+w1, rl-w1); if (w<=0) break; w1 += (size_t)w; }
}
close(c);
}
return NULL;
}
static int g_listen_made = 0;
static int make_listen(char *path, size_t n)
{
snprintf(path, n, "/tmp/meow_notify_intg_%d.sock", (int)getpid());
unlink(path);
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un a; memset(&a, 0, sizeof a);
a.sun_family = AF_UNIX; strncpy(a.sun_path, path, sizeof a.sun_path - 1);
if (bind(fd, (struct sockaddr*)&a, sizeof a) < 0 || listen(fd, 4) < 0) { close(fd); return -1; }
fcntl(fd, F_SETFL, O_NONBLOCK); /* 非阻塞 listener:accept() 可被 g_stop 截断 */
g_listen_fd = fd; g_listen_made = 1;
return 0;
}
static void stop_server(void)
{
if (g_listen_made) { g_stop = 1; close(g_listen_fd); g_listen_made = 0; }
}
static srec_t rec_at(int i)
{
srec_t r; pthread_mutex_lock(&g_mu); r = g_rec[i]; pthread_mutex_unlock(&g_mu); return r;
}
static int failures = 0;
static void check(const char *name, int cond)
{
printf("%s %s\n", cond ? "PASS" : "FAIL", name);
if (!cond) failures++;
}
int main(void)
{
setenv("MEOW_LOG_APP", "intgapp", 1);
char sock[108];
if (make_listen(sock, sizeof sock) != 0) { fprintf(stderr, "cannot listen\n"); return 2; }
setenv("MEOW_IPC_SOCK", sock, 1);
pthread_t th; pthread_create(&th, NULL, server, NULL);
/* S1 通用通知 */
meow_notify nt; memset(&nt, 0, sizeof nt);
nt.cat = MEOW_NOTIFY_CAT_GENERAL; nt.urgency = MEOW_NOTIFY_URG_NORMAL;
nt.title = "t1"; nt.timeout_ms = 0; nt.icon = "os.meow.hello/icon.png";
uint32_t id1 = meow_notify_send(&nt);
check("S1 send 返回本地 id=1", id1 == 1);
check("S1 active_count=1", meow_notify_active_count() == 1);
check("S1 stub 回 nid=101", rec_at(0).nid == 101);
check("S1 映射 urgency=NORMAL(1)", rec_at(0).n.urgency == MEOW_NOTIFY_URG_NORMAL);
check("S1 映射 icon→app_icon", !strcmp(rec_at(0).n.app_icon, "os.meow.hello/icon.png"));
/* S2 媒体通知:单例 + media=1 */
memset(&nt, 0, sizeof nt);
nt.cat = MEOW_NOTIFY_CAT_MEDIA; nt.title = "music"; nt.timeout_ms = -1;
uint32_t id2 = meow_notify_send(&nt);
check("S2 媒体返本地 id=2", id2 == 2);
check("S2 category=media", !strcmp(rec_at(1).n.category, "media"));
check("S2 media=1", rec_at(1).n.media == 1);
check("S2 expire=0xFFFFFFFF", rec_at(1).n.expire_timeout == 0xFFFFFFFFu);
/* S3 同类型再发(general 未满 4)→ 新本地 id */
memset(&nt, 0, sizeof nt);
nt.cat = MEOW_NOTIFY_CAT_GENERAL; nt.title = "t3"; nt.timeout_ms = 0;
uint32_t id3 = meow_notify_send(&nt);
check("S3 再发返本地 id=3", id3 == 3);
check("S3 第2条general nid=103", rec_at(2).nid == 103);
/* S4 cancel(id1) → DISMISS nid=101 */
int rc = meow_notify_cancel(id1);
check("S4 cancel 返回 1", rc == 1);
check("S4 stub 收到 MSG_NOTIFY_DISMISS", rec_at(3).type == MSG_NOTIFY_DISMISS);
check("S4 dismiss 负载 nid=101", rec_at(3).dismiss_id == 101);
check("S4 本地表已撤(count=2)", meow_notify_active_count() == 2);
/* S5 配额满 → 丢最旧 + replaces_id 复用被丢 nid。
当前 general 有 id3(1 条);再发 4 条到 4 条(第 4 条触顶后丢最旧)。 */
for (int i = 0; i < 4; i++) {
memset(&nt, 0, sizeof nt);
nt.cat = MEOW_NOTIFY_CAT_GENERAL; nt.title = "quota"; nt.timeout_ms = 0;
(void)meow_notify_send(&nt);
}
/* 现在 general 应仍有 4 条(第5条丢最旧 id3=本地,即被降级替换) */
check("S5 配额满后每类型仍=4", meow_notify_count_in_type(MEOW_NOTIFY_CAT_GENERAL) == 4);
/* 被丢最旧 = id3(第2条 general,本地 id=3),其 launcher nid=103(rec[2])。
触发丢最旧的是 S5 循环第 4 次 send = 第 7 条 NOTIFY(rec[7]),其 replaces_id==103。 */
check("S5 丢最旧后 send replaces_id=被丢nid(103)", rec_at(7).n.replaces_id == 103);
/* S5b update_progress:新发一条 progress → 本地 id → update → stub 捕获 MSG_NOTIFY_PROGRESS */
memset(&nt, 0, sizeof nt);
nt.cat = MEOW_NOTIFY_CAT_PROGRESS; nt.title = "prog"; nt.timeout_ms = 0;
nt.progress = 10;
uint32_t idp = meow_notify_send(&nt);
int ni = -1;
for (int i = 0; i < MAXCAP; i++) {
srec_t r = rec_at(i);
if (r.type == MSG_NOTIFY && !strcmp(r.n.summary, "prog")) { ni = i; break; }
}
check("S5b 找到 prog 通知帧", ni >= 0);
int rc_up = meow_notify_update_progress(idp, 70);
check("S5b update_progress 返回 1", rc_up == 1);
srec_t pr = rec_at(ni + 1);
check("S5b stub 捕获 MSG_NOTIFY_PROGRESS 帧", pr.type == MSG_NOTIFY_PROGRESS);
check("S5b progress nid=该通知 launcher nid", ni >= 0 && pr.prog.nid == rec_at(ni).nid);
check("S5b progress 载=70", pr.prog.progress == 70);
check("S5b update_progress(未知 id) 返回 0", meow_notify_update_progress(0xFFFFFF, 50) == 0);
stop_server();
pthread_join(th, NULL);
/* S6 无 launcher 降级 */
char dead[108]; snprintf(dead, sizeof dead, "/tmp/meow_notify_intg_dead_%d.sock", (int)getpid());
unlink(dead);
setenv("MEOW_IPC_SOCK", dead, 1);
memset(&nt, 0, sizeof nt);
nt.cat = MEOW_NOTIFY_CAT_EMAIL; nt.title = "no-launcher"; nt.timeout_ms = 0;
uint32_t id6 = meow_notify_send(&nt);
check("S6 无 launcher 仍返回本地 id(>0)", id6 > 0);
check("S6 无 launcher active_count 正常", meow_notify_active_count() >= 1);
check("S6 cancel 无 launcher 静默不崩", meow_notify_cancel(id6) == 1);
printf("\n%s (%d failure%s)\n", failures ? "RESULT: FAIL" : "RESULT: PASS",
failures, failures == 1 ? "" : "s");
return failures ? 1 : 0;
}