package user // 本文件覆盖裁决 06.4.2 的「每渠道账号配置的管理员 id 列表」白名单层:它是 channels.json // 的 adminIds[](design/08 §1.1)在内存里的落点,与 owner.yaml 的账号白名单取并集后共同 // 决定 owner 车道,且**不写回 owner.yaml**。 import ( "os" "path/filepath" "strings" "testing" ) func TestOwnerProfileSetPlatformAdmins(t *testing.T) { t.Parallel() p := &OwnerProfile{ID: "owner", DisplayName: "主人"} p.SetPlatformAdmins("qq-obv11", []string{"10001", " 10002 ", "10001", " "}) ids := p.PlatformAdmins("qq-obv11") if len(ids) != 2 || ids[0] != "10001" || ids[1] != "10002" { t.Fatalf("PlatformAdmins = %v, want [10001 10002](去空白 + 去重)", ids) } for _, id := range ids { if !p.IsOwner("qq-obv11", id) { t.Errorf("adminIds 命中的 %q 未判为主人", id) } } if p.IsOwner("qq-obv11", "10003") { t.Error("未声明的账号被判为主人") } if p.IsOwner("telegram", "10001") { t.Error("管理员 id 层跨平台串台了(应按平台隔离)") } if p.IsOwner("qq-obv11", "") { t.Error("空 accountId 不得命中白名单(fail-closed)") } // 整体替换:重新声明后旧 id 立即失效,channels.json 热重载不会留下悬挂管理员。 p.SetPlatformAdmins("qq-obv11", []string{"10002"}) if p.IsOwner("qq-obv11", "10001") { t.Error("SetPlatformAdmins 未整体替换") } // 空列表(含只有空白的列表)清空该平台的这一层。 p.SetPlatformAdmins("qq-obv11", []string{" "}) if p.IsOwner("qq-obv11", "10002") || p.PlatformAdmins("qq-obv11") != nil { t.Error("空列表应清空该平台的管理员层") } } func TestOwnerProfileAdminLayerConcurrentWithOwnerYaml(t *testing.T) { t.Parallel() // 两层来源共存:owner.yaml 的账号白名单与 channels.json 的 adminIds 都能判主。 p := &OwnerProfile{ ID: "owner", DisplayName: "主人", Accounts: []OwnerAccount{{Platform: "kook", AccountID: "329284282"}}, } p.SetPlatformAdmins("kook", []string{"555"}) if !p.IsOwner("kook", "329284282") || !p.IsOwner("kook", "555") { t.Fatalf("两层白名单未取并集: yaml=%v adminIds=%v", p.IsOwner("kook", "329284282"), p.IsOwner("kook", "555")) } } func TestOwnerProfileAdminLayerNotPersisted(t *testing.T) { t.Parallel() path := filepath.Join(t.TempDir(), "owner.yaml") p := &OwnerProfile{ID: "owner", DisplayName: "主人"} p.RegisterAccount("kook", "329284282") p.SetPlatformAdmins("qq-obv11", []string{"10001"}) if err := SaveOwnerProfile(path, p); err != nil { t.Fatalf("SaveOwnerProfile: %v", err) } data, err := os.ReadFile(path) if err != nil { t.Fatalf("read %s: %v", path, err) } if strings.Contains(string(data), "10001") { t.Error("adminIds 层被写回了 owner.yaml(应为只读来源 channels.json)") } reloaded, err := LoadOwnerProfile(path) if err != nil { t.Fatalf("LoadOwnerProfile: %v", err) } if !reloaded.IsOwner("kook", "329284282") { t.Error("owner.yaml 的账号白名单应在重载后保留") } if reloaded.IsOwner("qq-obv11", "10001") { t.Error("adminIds 层不应来自 owner.yaml") } }