Files
gpt-plus-gpt/internal/service/export_test.go
2026-03-15 20:48:19 +08:00

169 lines
4.3 KiB
Go

package service
import (
"archive/zip"
"bytes"
"encoding/json"
"strings"
"testing"
"gpt-plus/internal/db"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
func setupExportTestDB(t *testing.T) *gorm.DB {
t.Helper()
d, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil {
t.Fatalf("open db: %v", err)
}
d.AutoMigrate(&db.Account{})
return d
}
func TestExportSinglePlusAccount(t *testing.T) {
d := setupExportTestDB(t)
d.Create(&db.Account{
Email: "plus@test.com", Plan: "plus", Status: "active",
AccessToken: "at-123", RefreshToken: "rt-456", IDToken: "id-789",
AccountID: "acc-001",
})
data, filename, err := ExportAccounts(d, []uint{1}, "")
if err != nil {
t.Fatalf("export: %v", err)
}
if !strings.HasSuffix(filename, ".auth.json") {
t.Fatalf("filename = %q, want *.auth.json", filename)
}
var auth authFile
if err := json.Unmarshal(data, &auth); err != nil {
t.Fatalf("unmarshal: %v", err)
}
if auth.AccessToken != "at-123" {
t.Fatalf("access_token = %q", auth.AccessToken)
}
if auth.Tokens.AccountID != "acc-001" {
t.Fatalf("tokens.account_id = %q", auth.Tokens.AccountID)
}
}
func TestExportTeamWithSubAccounts(t *testing.T) {
d := setupExportTestDB(t)
owner := db.Account{
Email: "owner@test.com", Plan: "team_owner", Status: "active",
AccessToken: "owner-at", RefreshToken: "owner-rt",
AccountID: "team-acc", TeamWorkspaceID: "ws-123", WorkspaceToken: "ws-tok",
}
d.Create(&owner)
d.Create(&db.Account{
Email: "member@test.com", Plan: "team_member", Status: "active",
ParentID: &owner.ID, AccessToken: "mem-at", RefreshToken: "mem-rt",
})
data, filename, err := ExportAccounts(d, []uint{owner.ID}, "test")
if err != nil {
t.Fatalf("export: %v", err)
}
if !strings.HasSuffix(filename, ".zip") {
t.Fatalf("filename = %q, want *.zip", filename)
}
r, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
if err != nil {
t.Fatalf("open zip: %v", err)
}
if len(r.File) != 2 {
t.Fatalf("zip has %d files, want 2", len(r.File))
}
names := make(map[string]bool)
for _, f := range r.File {
names[f.Name] = true
}
if !names["owner@test.com.auth.json"] {
t.Fatal("missing owner auth file")
}
if !names["member@test.com.auth.json"] {
t.Fatal("missing member auth file")
}
}
func TestExportTeamOwnerUsesWorkspaceToken(t *testing.T) {
d := setupExportTestDB(t)
d.Create(&db.Account{
Email: "team@test.com", Plan: "team_owner", Status: "active",
AccessToken: "normal-at", WorkspaceToken: "ws-at",
TeamWorkspaceID: "team-ws-id", AccountID: "personal-acc",
})
data, _, err := ExportAccounts(d, []uint{1}, "")
if err != nil {
t.Fatalf("export: %v", err)
}
var auth authFile
json.Unmarshal(data, &auth)
if auth.AccessToken != "ws-at" {
t.Fatalf("should use workspace token, got %q", auth.AccessToken)
}
if auth.Tokens.AccountID != "team-ws-id" {
t.Fatalf("should use team workspace ID, got %q", auth.Tokens.AccountID)
}
}
func TestExportMultiplePlusAccounts(t *testing.T) {
d := setupExportTestDB(t)
d.Create(&db.Account{Email: "a@test.com", Plan: "plus", AccessToken: "at-a"})
d.Create(&db.Account{Email: "b@test.com", Plan: "plus", AccessToken: "at-b"})
data, filename, err := ExportAccounts(d, []uint{1, 2}, "batch")
if err != nil {
t.Fatalf("export: %v", err)
}
if !strings.HasSuffix(filename, ".zip") {
t.Fatalf("filename = %q, want *.zip for multiple", filename)
}
if !strings.Contains(filename, "batch") {
t.Fatalf("filename should contain note, got %q", filename)
}
r, _ := zip.NewReader(bytes.NewReader(data), int64(len(data)))
if len(r.File) != 2 {
t.Fatalf("zip has %d files, want 2", len(r.File))
}
}
func TestExportNotFound(t *testing.T) {
d := setupExportTestDB(t)
_, _, err := ExportAccounts(d, []uint{999}, "")
if err == nil {
t.Fatal("expected error for nonexistent account")
}
}
func TestBuildAuthFileFallbacks(t *testing.T) {
acct := &db.Account{
Email: "basic@test.com", AccessToken: "at-1", RefreshToken: "rt-1",
IDToken: "id-1", AccountID: "acc-1",
}
auth := buildAuthFile(acct)
if auth.AccessToken != "at-1" {
t.Fatalf("access_token = %q", auth.AccessToken)
}
if auth.Tokens.AccountID != "acc-1" {
t.Fatalf("tokens.account_id = %q", auth.Tokens.AccountID)
}
if auth.LastRefresh == "" {
t.Fatal("last_refresh should be set")
}
}