feat(t104): 多帳號同時看守——切換概念消滅
leo 架構依據:「它只是一個門,幾個帳號通過它同步並沒有影響」+ 「我不是 Google Drive……不提供暫存空間,daemon 工作輕巧,多帳號只是頁簽問題」 (D-daemon-not-Drive)。 Accounts[] 每帳號獨立連線+資料夾;舊 config 冪等遷移 accounts[0]; 逐帳號同步一敗不擋全;status.json 分帳;托盤每帳號一分組; 「連上知識庫」→「+新增帳號…」(append 非替換);t86 切換清空退役; t101 刪除作用於正確帳號。+873/-149、collector 5+tray 5 新測試, 兩模組 go test 全綠(總管親跑)。 (實作=子 CC;驗證+commit=總管)
This commit is contained in:
@@ -306,3 +306,138 @@ func TestDirectConfigPreservesClaudeBin(t *testing.T) {
|
||||
t.Errorf("round-trip 不一致:got %q, want %q", back.ClaudeBin, c.ClaudeBin)
|
||||
}
|
||||
}
|
||||
|
||||
// ── t104:多帳號同時看守 ──────────────────────────────────────────────────────────
|
||||
|
||||
// TestAddOrUpdateAccount_NewAccount:空 accounts → 加入新帳號。
|
||||
func TestAddOrUpdateAccount_NewAccount(t *testing.T) {
|
||||
cfg := &directConfig{}
|
||||
r := &daemonConfigResp{}
|
||||
r.Config.CypherURL = "https://instance1.workers.dev"
|
||||
r.Config.Namespace = "ns1"
|
||||
r.Config.Email = "user@a.com"
|
||||
r.Config.InstanceName = "Work"
|
||||
|
||||
isNew := addOrUpdateAccount(cfg, r)
|
||||
if !isNew {
|
||||
t.Error("新帳號應回 true")
|
||||
}
|
||||
if len(cfg.Accounts) != 1 {
|
||||
t.Fatalf("應新增 1 個帳號,got %d", len(cfg.Accounts))
|
||||
}
|
||||
if cfg.Accounts[0].Email != "user@a.com" {
|
||||
t.Errorf("email 錯:%s", cfg.Accounts[0].Email)
|
||||
}
|
||||
if cfg.Accounts[0].InstanceName != "Work" {
|
||||
t.Errorf("instance_name 錯:%s", cfg.Accounts[0].InstanceName)
|
||||
}
|
||||
}
|
||||
|
||||
// TestAddOrUpdateAccount_SameHostUpdates:同 host → 更新連線資訊,WatchFolders 不清空。
|
||||
func TestAddOrUpdateAccount_SameHostUpdates(t *testing.T) {
|
||||
cfg := &directConfig{
|
||||
Accounts: []accountCfg{{
|
||||
CypherURL: "https://instance1.workers.dev",
|
||||
Namespace: "ns1",
|
||||
Email: "old@a.com",
|
||||
WatchFolders: []string{"/path/to/folder"},
|
||||
}},
|
||||
}
|
||||
r := &daemonConfigResp{}
|
||||
r.Config.CypherURL = "https://instance1.workers.dev"
|
||||
r.Config.Namespace = "ns1"
|
||||
r.Config.Email = "new@a.com"
|
||||
|
||||
isNew := addOrUpdateAccount(cfg, r)
|
||||
if isNew {
|
||||
t.Error("同 host 應回 false(更新,非新增)")
|
||||
}
|
||||
if len(cfg.Accounts) != 1 {
|
||||
t.Fatalf("不應新增帳號,got %d", len(cfg.Accounts))
|
||||
}
|
||||
if cfg.Accounts[0].Email != "new@a.com" {
|
||||
t.Errorf("email 未更新:%s", cfg.Accounts[0].Email)
|
||||
}
|
||||
if len(cfg.Accounts[0].WatchFolders) == 0 {
|
||||
t.Error("同 host 更新不應清空資料夾(t86 退役)")
|
||||
}
|
||||
}
|
||||
|
||||
// TestAddOrUpdateAccount_DifferentHostAdds:不同 host → 兩個帳號並存。
|
||||
func TestAddOrUpdateAccount_DifferentHostAdds(t *testing.T) {
|
||||
cfg := &directConfig{
|
||||
Accounts: []accountCfg{{
|
||||
CypherURL: "https://instance1.workers.dev",
|
||||
Namespace: "ns1",
|
||||
}},
|
||||
}
|
||||
r := &daemonConfigResp{}
|
||||
r.Config.CypherURL = "https://instance2.workers.dev"
|
||||
r.Config.Namespace = "ns2"
|
||||
|
||||
isNew := addOrUpdateAccount(cfg, r)
|
||||
if !isNew {
|
||||
t.Error("不同 host 應回 true(新增)")
|
||||
}
|
||||
if len(cfg.Accounts) != 2 {
|
||||
t.Fatalf("應有 2 個帳號,got %d", len(cfg.Accounts))
|
||||
}
|
||||
}
|
||||
|
||||
// TestRemoveAccountWatchFolder_CorrectAccount:刪帳號 A 的資料夾不影響帳號 B(t104+t101)。
|
||||
func TestRemoveAccountWatchFolder_CorrectAccount(t *testing.T) {
|
||||
cfg := &directConfig{
|
||||
Accounts: []accountCfg{
|
||||
{CypherURL: "https://a.workers.dev", WatchFolders: []string{"/folder1", "/folder2"}},
|
||||
{CypherURL: "https://b.workers.dev", WatchFolders: []string{"/folder3"}},
|
||||
},
|
||||
}
|
||||
removeAccountWatchFolder(cfg, 0, "/folder1")
|
||||
if len(cfg.Accounts[0].WatchFolders) != 1 {
|
||||
t.Fatalf("account[0] 應剩 1 個資料夾,got %v", cfg.Accounts[0].WatchFolders)
|
||||
}
|
||||
if cfg.Accounts[0].WatchFolders[0] != "/folder2" {
|
||||
t.Errorf("account[0] 剩餘應是 /folder2,got %s", cfg.Accounts[0].WatchFolders[0])
|
||||
}
|
||||
if len(cfg.Accounts[1].WatchFolders) != 1 || cfg.Accounts[1].WatchFolders[0] != "/folder3" {
|
||||
t.Errorf("account[1] 資料夾不應改變,got %v", cfg.Accounts[1].WatchFolders)
|
||||
}
|
||||
}
|
||||
|
||||
// TestAccountDisplayName:暱稱 > email > host(t26 延伸)。
|
||||
func TestAccountDisplayName(t *testing.T) {
|
||||
cases := []struct {
|
||||
acc accountCfg
|
||||
want string
|
||||
}{
|
||||
{accountCfg{InstanceName: "書房", Email: "a@b.com", CypherURL: "https://c.dev"}, "書房"},
|
||||
{accountCfg{Email: "a@b.com", CypherURL: "https://c.dev"}, "a@b.com"},
|
||||
{accountCfg{CypherURL: "https://arcrun-cypher-executor.acct.workers.dev"}, "arcrun-cypher-executor.acct.workers.dev"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := accountDisplayName(c.acc)
|
||||
if got != c.want {
|
||||
t.Errorf("accountDisplayName(%+v) = %q, want %q", c.acc, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestDirectConfigFolders_MultiAccount:多帳號 Folders() 彙整所有帳號資料夾。
|
||||
func TestDirectConfigFolders_MultiAccount(t *testing.T) {
|
||||
cfg := &directConfig{
|
||||
Accounts: []accountCfg{
|
||||
{WatchFolders: []string{"/a", "/b"}},
|
||||
{WatchFolders: []string{"/c"}},
|
||||
},
|
||||
}
|
||||
got := cfg.Folders()
|
||||
want := []string{"/a", "/b", "/c"}
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf("Folders() = %v, want %v", got, want)
|
||||
}
|
||||
for i := range want {
|
||||
if got[i] != want[i] {
|
||||
t.Errorf("Folders()[%d] = %q, want %q", i, got[i], want[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user