gcli2api / internal /upstream /desktop_test.go
a3216's picture
chore: 同步到上游 1.12.0-panel + 凭证同步/独立启动器/保活
6d60378 verified
Raw History Blame Contribute Delete
4.36 kB
package upstream
import (
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"testing"
"github.com/linguo2625469/workbuddy2api-panel/internal/auth"
)
// TestReportDesktopEventFingerprint 断言桌面指纹上报:走 chatBase、UA 为桌面形状、
// 事件数组自动注入 workbuddy-desktop 公共指纹(覆盖同名业务键)。
func TestReportDesktopEventFingerprint(t *testing.T) {
var got []map[string]any
var gotUA string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/v2/report" {
t.Errorf("path=%s want /v2/report", r.URL.Path)
}
gotUA = r.Header.Get("User-Agent")
if r.Header.Get("X-User-Id") != "u-dt" {
t.Errorf("X-User-Id=%q want u-dt", r.Header.Get("X-User-Id"))
}
if r.Header.Get("X-Product") != "SaaS" {
t.Errorf("X-Product=%q want SaaS", r.Header.Get("X-Product"))
}
raw, _ := io.ReadAll(r.Body)
if err := json.Unmarshal(raw, &got); err != nil {
t.Fatalf("body must be array: %v", err)
}
w.Write([]byte(`{"code":0,"msg":"OK"}`))
}))
defer srv.Close()
c := &Client{HTTP: srv.Client(), ChatBaseCN: srv.URL}
err := c.ReportDesktopEvent(&auth.Auth{AccessToken: "at", UID: "u-dt", Nickname: "RenJie"},
DesktopEvent{"eventCode": "agent_task_created", "mode": "craft"})
if err != nil {
t.Fatalf("report desktop: %v", err)
}
if gotUA != desktopUA {
t.Errorf("UA=%q want %q", gotUA, desktopUA)
}
if len(got) != 1 {
t.Fatalf("events=%d want 1", len(got))
}
ev := got[0]
if ev["extName"] != "workbuddy-desktop" {
t.Errorf("extName=%v want workbuddy-desktop", ev["extName"])
}
if ev["ideType"] != "WorkBuddy" || ev["ideName"] != "WorkBuddy" {
t.Errorf("ideType/ideName=%v/%v want WorkBuddy", ev["ideType"], ev["ideName"])
}
if ev["userId"] != "u-dt" {
t.Errorf("userId=%v want u-dt", ev["userId"])
}
if ev["userNickname"] != "RenJie" {
t.Errorf("userNickname=%v want RenJie", ev["userNickname"])
}
if ev["mode"] != "craft" {
t.Errorf("业务字段 mode=%v 被指纹覆盖或缺失", ev["mode"])
}
// machineId 应为 uid 稳定派生(36 hex)。
if len(ev["machineId"].(string)) != 36 {
t.Errorf("machineId 长度=%d want 36", len(ev["machineId"].(string)))
}
}
// TestDesktopChatSequenceShape 断言完整对话事件链的事件码顺序与关键字段。
func TestDesktopChatSequenceShape(t *testing.T) {
events := DesktopChatSequence("conv-1", "req-1", "msg-1", "fast-model", "fast-model")
wantCodes := []string{
"agent_task_created", "chat_message_send", "chat_request_send",
"chat_message_response", "chat_message_status", "chat_request_response",
}
if len(events) != len(wantCodes) {
t.Fatalf("events=%d want %d", len(events), len(wantCodes))
}
for i, want := range wantCodes {
if events[i]["eventCode"] != want {
t.Errorf("events[%d].eventCode=%v want %v", i, events[i]["eventCode"], want)
}
}
resp := events[3]
if resp["isSuccessful"] != true {
t.Errorf("chat_message_response.isSuccessful=%v want true(RichMeow 判据)", resp["isSuccessful"])
}
if resp["finishReason"] != "stop" {
t.Errorf("finishReason=%v want stop", resp["finishReason"])
}
if resp["conversationId"] != "conv-1" {
t.Errorf("conversationId=%v want conv-1", resp["conversationId"])
}
}
// TestSetAppearanceTheme 断言主题设置端点形状(点亮 Hp_Appearance 的 API)。
func TestSetAppearanceTheme(t *testing.T) {
var got map[string]any
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/v2/user-asset/appearance/set" {
t.Errorf("path=%s want /v2/user-asset/appearance/set", r.URL.Path)
}
if r.Header.Get("User-Agent") != desktopUA {
t.Errorf("UA=%q want desktop UA", r.Header.Get("User-Agent"))
}
raw, _ := io.ReadAll(r.Body)
json.Unmarshal(raw, &got)
w.Write([]byte(`{"code":0,"msg":"OK"}`))
}))
defer srv.Close()
c := &Client{HTTP: srv.Client(), ChatBaseCN: srv.URL}
if err := c.SetAppearanceTheme(&auth.Auth{AccessToken: "at", UID: "u1"}, "theme-tkmw7j"); err != nil {
t.Fatalf("set theme: %v", err)
}
if got["kind"] != "theme" || got["resource_key"] != "theme-tkmw7j" {
t.Errorf("body=%v want kind=theme resource_key=theme-tkmw7j", got)
}
}