Add 'sdk/' from commit '2e7561d74f75de05dd7fb362f203f600afb451d7'

git-subtree-dir: sdk
git-subtree-mainline: 17a972d46f
git-subtree-split: 2e7561d74f
This commit is contained in:
MeowOS committed 2026-09-01 21:08:40 +08:00
commit f44e3bc6d0
85 files changed
+23811

No files matched your search

+224
View File
@@ -0,0 +1,224 @@
/*
* 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;
}