183 lines
5.8 KiB
Go
183 lines
5.8 KiB
Go
package reconcile
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"sub2api-cn-relay-manager/internal/host/sub2api"
|
|
"sub2api-cn-relay-manager/internal/pack"
|
|
"sub2api-cn-relay-manager/internal/store/sqlite"
|
|
)
|
|
|
|
func TestAccountIDFromProbeSummary(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
accountID, err := AccountIDFromProbeSummary(`{"account_id":" account_1 "}`)
|
|
if err != nil {
|
|
t.Fatalf("AccountIDFromProbeSummary() error = %v", err)
|
|
}
|
|
if accountID != "account_1" {
|
|
t.Fatalf("accountID = %q, want account_1", accountID)
|
|
}
|
|
if _, err := AccountIDFromProbeSummary(`{`); err == nil {
|
|
t.Fatal("AccountIDFromProbeSummary() error = nil, want JSON decode error")
|
|
}
|
|
blank, err := AccountIDFromProbeSummary("")
|
|
if err != nil {
|
|
t.Fatalf("AccountIDFromProbeSummary(blank) error = %v", err)
|
|
}
|
|
if blank != "" {
|
|
t.Fatalf("blank accountID = %q, want empty", blank)
|
|
}
|
|
}
|
|
|
|
func TestDiffManagedResourcesCountsMissingAndExtra(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
missing, extra := DiffManagedResources(
|
|
[]sqlite.ManagedResource{
|
|
{ResourceType: "group", HostResourceID: "group_1"},
|
|
{ResourceType: "account", HostResourceID: "account_1"},
|
|
},
|
|
sub2api.ManagedResourceSnapshot{
|
|
Groups: []sub2api.NamedResource{{ID: "group_1"}},
|
|
Accounts: []sub2api.NamedResource{{ID: "account_2"}},
|
|
},
|
|
)
|
|
if missing != 1 || extra != 1 {
|
|
t.Fatalf("DiffManagedResources() = (%d, %d), want (1, 1)", missing, extra)
|
|
}
|
|
}
|
|
|
|
func TestDeriveHealthyAccessStatus(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
closureType string
|
|
want string
|
|
}{
|
|
{name: "subscription", closureType: accessModeSubscription, want: accessStatusSubscriptionReady},
|
|
{name: "self-service", closureType: accessModeSelfService, want: accessStatusSelfServiceReady},
|
|
{name: "unknown", closureType: "other", want: "unknown"},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got := DeriveHealthyAccessStatus(tc.closureType); got != tc.want {
|
|
t.Fatalf("DeriveHealthyAccessStatus(%q) = %q, want %q", tc.closureType, got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuildManagedResourceListRequestUsesModeSpecificNames(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
provider := pack.ProviderManifest{ProviderID: "deepseek"}
|
|
subscriptionReq := buildManagedResourceListRequest(provider, accessModeSubscription)
|
|
if subscriptionReq.PlanName == "" {
|
|
t.Fatal("subscription PlanName = empty, want mode-specific plan")
|
|
}
|
|
if subscriptionReq.AccountNamePrefix != "deepseek-" {
|
|
t.Fatalf("subscription AccountNamePrefix = %q, want deepseek-", subscriptionReq.AccountNamePrefix)
|
|
}
|
|
|
|
selfServiceReq := buildManagedResourceListRequest(provider, accessModeSelfService)
|
|
if selfServiceReq.PlanName != "" {
|
|
t.Fatalf("selfService PlanName = %q, want empty", selfServiceReq.PlanName)
|
|
}
|
|
if selfServiceReq.GroupName == subscriptionReq.GroupName {
|
|
t.Fatalf("GroupName = %q, want different names per access mode", selfServiceReq.GroupName)
|
|
}
|
|
}
|
|
|
|
func TestAccountValidationStatusTreatsResponsesRaceAsWarning(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
status := accountValidationStatus(sub2api.ProbeResult{
|
|
OK: false,
|
|
Status: "failed",
|
|
Message: "账号本身可正常使用,但当前测试接口仅支持 Responses API 路径。请直接通过实际 API 调用验证。",
|
|
}, true)
|
|
if status != accountStatusWarning {
|
|
t.Fatalf("accountValidationStatus() = %q, want %q", status, accountStatusWarning)
|
|
}
|
|
}
|
|
|
|
func TestAccountValidationStatusTreatsTransientProbeFailureAsWarning(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
status := accountValidationStatus(sub2api.ProbeResult{
|
|
OK: false,
|
|
Status: "failed",
|
|
Message: "API returned 503: upstream service unavailable, retry later",
|
|
}, true)
|
|
if status != accountStatusWarning {
|
|
t.Fatalf("accountValidationStatus() = %q, want %q", status, accountStatusWarning)
|
|
}
|
|
}
|
|
|
|
func TestNormalizedUniqueAccountIDs(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
got := normalizedUniqueAccountIDs([]string{" account_1 ", "", "account_2", "account_1", " "})
|
|
want := []string{"account_1", "account_2"}
|
|
if len(got) != len(want) {
|
|
t.Fatalf("normalizedUniqueAccountIDs() len = %d, want %d; values = %v", len(got), len(want), got)
|
|
}
|
|
for i := range want {
|
|
if got[i] != want[i] {
|
|
t.Fatalf("normalizedUniqueAccountIDs()[%d] = %q, want %q; values = %v", i, got[i], want[i], got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAccessClosureTypeReturnsLatestTrimmedType(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if got := accessClosureType(nil); got != "" {
|
|
t.Fatalf("accessClosureType(nil) = %q, want empty", got)
|
|
}
|
|
got := accessClosureType([]sqlite.AccessClosureRecord{
|
|
{ClosureType: " subscription "},
|
|
{ClosureType: " self_service "},
|
|
})
|
|
if got != accessModeSelfService {
|
|
t.Fatalf("accessClosureType() = %q, want %q", got, accessModeSelfService)
|
|
}
|
|
}
|
|
|
|
func TestClassifyHistoricalAccountNoiseOnlyKeepsPrefixedOutOfBatchAccounts(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
got := classifyHistoricalAccountNoise(
|
|
[]sqlite.ManagedResource{
|
|
{ResourceType: "account", HostResourceID: "account_1"},
|
|
{ResourceType: "group", HostResourceID: "group_1"},
|
|
},
|
|
[]sub2api.NamedResource{
|
|
{ID: "account_1", Name: "deepseek-01"},
|
|
{ID: "account_2", Name: "deepseek-02"},
|
|
{ID: "account_3", Name: "other-03"},
|
|
{ID: " ", Name: "deepseek-04"},
|
|
},
|
|
"deepseek-",
|
|
)
|
|
if len(got) != 1 {
|
|
t.Fatalf("classifyHistoricalAccountNoise() len = %d, want 1; values = %+v", len(got), got)
|
|
}
|
|
if got[0].ID != "account_2" || got[0].Name != "deepseek-02" {
|
|
t.Fatalf("classifyHistoricalAccountNoise()[0] = %+v, want account_2/deepseek-02", got[0])
|
|
}
|
|
}
|
|
|
|
func TestGatewayAccessReadyRequiresCompletionSuccess(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if gatewayAccessReady(sub2api.GatewayAccessResult{OK: true, HasExpectedModel: true}) {
|
|
t.Fatal("gatewayAccessReady() = true, want false without completion success")
|
|
}
|
|
if !gatewayAccessReady(sub2api.GatewayAccessResult{OK: true, HasExpectedModel: true, CompletionOK: true}) {
|
|
t.Fatal("gatewayAccessReady() = false, want true when gateway and completion are ready")
|
|
}
|
|
}
|