Downgrade the first third-party account test 403 to an advisory warning when models are already present, and retry transient gateway completion 503 responses during access closure. Add regression coverage for the probe race and completion retry paths, update the execution board, and store the final v0.1.129 Kimi A7M fresh-host acceptance artifact that now reaches succeeded/active/subscription_ready.
527 lines
19 KiB
Go
527 lines
19 KiB
Go
package provision
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
_ "modernc.org/sqlite"
|
|
"sub2api-cn-relay-manager/internal/host/sub2api"
|
|
"sub2api-cn-relay-manager/internal/pack"
|
|
"sub2api-cn-relay-manager/internal/store/sqlite"
|
|
)
|
|
|
|
func TestRuntimeImportServicePersistsOperationalState(t *testing.T) {
|
|
store := openProvisionTestStore(t)
|
|
defer closeProvisionTestStore(t, store)
|
|
|
|
seedProvisionHost(t, store, "host-1", "https://sub2api.example.com")
|
|
|
|
host := &fakeHostAdapter{
|
|
batchAccounts: []sub2api.AccountRef{{ID: "account_1"}, {ID: "account_2"}},
|
|
testResults: map[string]sub2api.ProbeResult{
|
|
"account_1": {OK: true, Status: "passed"},
|
|
"account_2": {OK: true, Status: "passed"},
|
|
},
|
|
models: map[string][]sub2api.AccountModel{
|
|
"account_1": {{ID: "deepseek-chat"}},
|
|
"account_2": {{ID: "deepseek-chat"}},
|
|
},
|
|
gatewayResult: sub2api.GatewayAccessResult{OK: true, StatusCode: 200, HasExpectedModel: true, Models: []string{"deepseek-chat"}},
|
|
}
|
|
|
|
svc := NewRuntimeImportService(store, host)
|
|
result, err := svc.Import(context.Background(), RuntimeImportRequest{
|
|
HostID: "host-1",
|
|
HostBaseURL: "https://sub2api.example.com",
|
|
Pack: pack.LoadedPack{
|
|
Manifest: pack.Manifest{PackID: "openai-cn-pack", Version: "1.0.0", TargetHost: "sub2api", MinHostVersion: "0.1.126", MaxHostVersion: "0.2.x"},
|
|
Checksum: "checksum-1",
|
|
},
|
|
Provider: sampleProviderManifest(),
|
|
Mode: ImportModePartial,
|
|
Keys: []string{" key-1 ", "key-2", "key-1"},
|
|
Access: AccessRequest{
|
|
Mode: AccessModeSelfService,
|
|
ProbeAPIKey: "user-key",
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("RuntimeImportService.Import() error = %v", err)
|
|
}
|
|
if result.BatchID <= 0 {
|
|
t.Fatalf("BatchID = %d, want positive id", result.BatchID)
|
|
}
|
|
if result.Report.BatchStatus != BatchStatusSucceeded {
|
|
t.Fatalf("BatchStatus = %q, want %q", result.Report.BatchStatus, BatchStatusSucceeded)
|
|
}
|
|
|
|
if got := queryCount(t, store.SQLDB(), "hosts"); got != 1 {
|
|
t.Fatalf("hosts row count = %d, want 1", got)
|
|
}
|
|
if got := queryCount(t, store.SQLDB(), "packs"); got != 1 {
|
|
t.Fatalf("packs row count = %d, want 1", got)
|
|
}
|
|
if got := queryCount(t, store.SQLDB(), "providers"); got != 1 {
|
|
t.Fatalf("providers row count = %d, want 1", got)
|
|
}
|
|
if got := queryCount(t, store.SQLDB(), "import_batches"); got != 1 {
|
|
t.Fatalf("import_batches row count = %d, want 1", got)
|
|
}
|
|
if got := queryCount(t, store.SQLDB(), "import_batch_items"); got != 2 {
|
|
t.Fatalf("import_batch_items row count = %d, want 2", got)
|
|
}
|
|
if got := queryCount(t, store.SQLDB(), "managed_resources"); got != 4 {
|
|
t.Fatalf("managed_resources row count = %d, want 4", got)
|
|
}
|
|
if got := queryCount(t, store.SQLDB(), "probe_results"); got != 2 {
|
|
t.Fatalf("probe_results row count = %d, want 2", got)
|
|
}
|
|
if got := queryCount(t, store.SQLDB(), "access_closure_records"); got != 1 {
|
|
t.Fatalf("access_closure_records row count = %d, want 1", got)
|
|
}
|
|
|
|
var batchStatus string
|
|
var accessStatus string
|
|
if err := store.SQLDB().QueryRowContext(context.Background(), "SELECT batch_status, access_status FROM import_batches WHERE id = ?", result.BatchID).Scan(&batchStatus, &accessStatus); err != nil {
|
|
t.Fatalf("query import batch state: %v", err)
|
|
}
|
|
if batchStatus != BatchStatusSucceeded {
|
|
t.Fatalf("persisted batch_status = %q, want %q", batchStatus, BatchStatusSucceeded)
|
|
}
|
|
if accessStatus != AccessStatusSelfServiceReady {
|
|
t.Fatalf("persisted access_status = %q, want %q", accessStatus, AccessStatusSelfServiceReady)
|
|
}
|
|
|
|
var fingerprint string
|
|
var accountStatus string
|
|
if err := store.SQLDB().QueryRowContext(context.Background(), "SELECT key_fingerprint, account_status FROM import_batch_items ORDER BY id LIMIT 1").Scan(&fingerprint, &accountStatus); err != nil {
|
|
t.Fatalf("query import batch item: %v", err)
|
|
}
|
|
if fingerprint == "key-1" || fingerprint == "key-2" || len(fingerprint) < 10 {
|
|
t.Fatalf("key_fingerprint = %q, want hashed fingerprint instead of raw key", fingerprint)
|
|
}
|
|
if accountStatus != "passed" {
|
|
t.Fatalf("account_status = %q, want passed", accountStatus)
|
|
}
|
|
}
|
|
|
|
func TestRuntimeImportServicePersistsFailedBatchAfterStrictRollback(t *testing.T) {
|
|
store := openProvisionTestStore(t)
|
|
defer closeProvisionTestStore(t, store)
|
|
|
|
seedProvisionHost(t, store, "host-1", "https://sub2api.example.com")
|
|
|
|
host := &fakeHostAdapter{
|
|
batchAccounts: []sub2api.AccountRef{{ID: "account_1"}, {ID: "account_2"}},
|
|
testResults: map[string]sub2api.ProbeResult{
|
|
"account_1": {OK: true, Status: "passed"},
|
|
"account_2": {OK: false, Status: "failed", Message: "bad key"},
|
|
},
|
|
models: map[string][]sub2api.AccountModel{
|
|
"account_1": {{ID: "deepseek-chat"}},
|
|
"account_2": {{ID: "deepseek-chat"}},
|
|
},
|
|
}
|
|
|
|
svc := NewRuntimeImportService(store, host)
|
|
result, err := svc.Import(context.Background(), RuntimeImportRequest{
|
|
HostID: "host-1",
|
|
HostBaseURL: "https://sub2api.example.com",
|
|
Pack: pack.LoadedPack{
|
|
Manifest: pack.Manifest{PackID: "openai-cn-pack", Version: "1.0.0", TargetHost: "sub2api", MinHostVersion: "0.1.126", MaxHostVersion: "0.2.x"},
|
|
Checksum: "checksum-1",
|
|
},
|
|
Provider: sampleProviderManifest(),
|
|
Mode: ImportModeStrict,
|
|
Keys: []string{"key-1", "key-2"},
|
|
Access: AccessRequest{
|
|
Mode: AccessModeSelfService,
|
|
ProbeAPIKey: "user-key",
|
|
},
|
|
})
|
|
if err == nil {
|
|
t.Fatal("RuntimeImportService.Import() error = nil, want strict failure")
|
|
}
|
|
if result.BatchID <= 0 {
|
|
t.Fatalf("BatchID = %d, want positive id", result.BatchID)
|
|
}
|
|
|
|
var batchStatus string
|
|
var accessStatus string
|
|
if err := store.SQLDB().QueryRowContext(context.Background(), "SELECT batch_status, access_status FROM import_batches WHERE id = ?", result.BatchID).Scan(&batchStatus, &accessStatus); err != nil {
|
|
t.Fatalf("query failed import batch state: %v", err)
|
|
}
|
|
if batchStatus != BatchStatusFailed {
|
|
t.Fatalf("persisted batch_status = %q, want %q", batchStatus, BatchStatusFailed)
|
|
}
|
|
if accessStatus != AccessStatusBroken {
|
|
t.Fatalf("persisted access_status = %q, want %q", accessStatus, AccessStatusBroken)
|
|
}
|
|
if got := queryCount(t, store.SQLDB(), "managed_resources"); got != 0 {
|
|
t.Fatalf("managed_resources row count = %d, want 0 after strict rollback", got)
|
|
}
|
|
if got := queryCount(t, store.SQLDB(), "probe_results"); got != 2 {
|
|
t.Fatalf("probe_results row count = %d, want 2", got)
|
|
}
|
|
if got := queryCount(t, store.SQLDB(), "access_closure_records"); got != 1 {
|
|
t.Fatalf("access_closure_records row count = %d, want 1", got)
|
|
}
|
|
}
|
|
|
|
func TestRuntimeImportServicePersistsWarningAccountStatusForAdvisoryProbeFailure(t *testing.T) {
|
|
store := openProvisionTestStore(t)
|
|
defer closeProvisionTestStore(t, store)
|
|
|
|
seedProvisionHost(t, store, "host-1", "https://sub2api.example.com")
|
|
|
|
host := &fakeHostAdapter{
|
|
batchAccounts: []sub2api.AccountRef{{ID: "account_1"}},
|
|
testResults: map[string]sub2api.ProbeResult{
|
|
"account_1": {
|
|
OK: false,
|
|
Status: "failed",
|
|
Message: "账号本身可正常使用,但当前测试接口仅支持 Responses API 路径。请直接通过实际 API 调用验证。",
|
|
},
|
|
},
|
|
models: map[string][]sub2api.AccountModel{
|
|
"account_1": {{ID: "deepseek-chat"}},
|
|
},
|
|
gatewayResult: sub2api.GatewayAccessResult{
|
|
OK: true,
|
|
StatusCode: 200,
|
|
HasExpectedModel: true,
|
|
Models: []string{"deepseek-chat"},
|
|
CompletionOK: true,
|
|
CompletionStatus: 200,
|
|
},
|
|
}
|
|
|
|
svc := NewRuntimeImportService(store, host)
|
|
result, err := svc.Import(context.Background(), RuntimeImportRequest{
|
|
HostID: "host-1",
|
|
HostBaseURL: "https://sub2api.example.com",
|
|
Pack: pack.LoadedPack{
|
|
Manifest: pack.Manifest{PackID: "openai-cn-pack", Version: "1.0.0", TargetHost: "sub2api", MinHostVersion: "0.1.126", MaxHostVersion: "0.2.x"},
|
|
Checksum: "checksum-1",
|
|
},
|
|
Provider: sampleProviderManifest(),
|
|
Mode: ImportModePartial,
|
|
Keys: []string{"key-1"},
|
|
Access: AccessRequest{
|
|
Mode: AccessModeSelfService,
|
|
ProbeAPIKey: "user-key",
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("RuntimeImportService.Import() error = %v", err)
|
|
}
|
|
if result.Report.BatchStatus != BatchStatusSucceeded {
|
|
t.Fatalf("BatchStatus = %q, want %q", result.Report.BatchStatus, BatchStatusSucceeded)
|
|
}
|
|
|
|
var accountStatus string
|
|
var summary string
|
|
if err := store.SQLDB().QueryRowContext(context.Background(), "SELECT account_status, probe_summary_json FROM import_batch_items WHERE batch_id = ? ORDER BY id LIMIT 1", result.BatchID).Scan(&accountStatus, &summary); err != nil {
|
|
t.Fatalf("query import batch item: %v", err)
|
|
}
|
|
if accountStatus != AccountStatusWarning {
|
|
t.Fatalf("account_status = %q, want %q", accountStatus, AccountStatusWarning)
|
|
}
|
|
if !strings.Contains(summary, "\"probe_advisory\":true") {
|
|
t.Fatalf("probe_summary_json = %s, want probe_advisory=true", summary)
|
|
}
|
|
}
|
|
|
|
func TestRuntimeImportServicePersistsWarningAccountStatusForForbiddenProbeRace(t *testing.T) {
|
|
store := openProvisionTestStore(t)
|
|
defer closeProvisionTestStore(t, store)
|
|
|
|
seedProvisionHost(t, store, "host-1", "https://sub2api.example.com")
|
|
|
|
host := &fakeHostAdapter{
|
|
batchAccounts: []sub2api.AccountRef{{ID: "account_1"}},
|
|
testResults: map[string]sub2api.ProbeResult{
|
|
"account_1": {
|
|
OK: false,
|
|
Status: "failed",
|
|
Message: "API returned 403: Forbidden",
|
|
},
|
|
},
|
|
models: map[string][]sub2api.AccountModel{
|
|
"account_1": {{ID: "deepseek-chat"}},
|
|
},
|
|
gatewayResult: sub2api.GatewayAccessResult{
|
|
OK: true,
|
|
StatusCode: 200,
|
|
HasExpectedModel: true,
|
|
Models: []string{"deepseek-chat"},
|
|
CompletionOK: true,
|
|
CompletionStatus: 200,
|
|
},
|
|
}
|
|
|
|
svc := NewRuntimeImportService(store, host)
|
|
result, err := svc.Import(context.Background(), RuntimeImportRequest{
|
|
HostID: "host-1",
|
|
HostBaseURL: "https://sub2api.example.com",
|
|
Pack: pack.LoadedPack{
|
|
Manifest: pack.Manifest{PackID: "openai-cn-pack", Version: "1.0.0", TargetHost: "sub2api", MinHostVersion: "0.1.126", MaxHostVersion: "0.2.x"},
|
|
Checksum: "checksum-1",
|
|
},
|
|
Provider: sampleProviderManifest(),
|
|
Mode: ImportModePartial,
|
|
Keys: []string{"key-1"},
|
|
Access: AccessRequest{
|
|
Mode: AccessModeSelfService,
|
|
ProbeAPIKey: "user-key",
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("RuntimeImportService.Import() error = %v", err)
|
|
}
|
|
if result.Report.BatchStatus != BatchStatusSucceeded {
|
|
t.Fatalf("BatchStatus = %q, want %q", result.Report.BatchStatus, BatchStatusSucceeded)
|
|
}
|
|
|
|
var accountStatus string
|
|
var summary string
|
|
if err := store.SQLDB().QueryRowContext(context.Background(), "SELECT account_status, probe_summary_json FROM import_batch_items WHERE batch_id = ? ORDER BY id LIMIT 1", result.BatchID).Scan(&accountStatus, &summary); err != nil {
|
|
t.Fatalf("query import batch item: %v", err)
|
|
}
|
|
if accountStatus != AccountStatusWarning {
|
|
t.Fatalf("account_status = %q, want %q", accountStatus, AccountStatusWarning)
|
|
}
|
|
if !strings.Contains(summary, "\"probe_advisory\":true") {
|
|
t.Fatalf("probe_summary_json = %s, want probe_advisory=true", summary)
|
|
}
|
|
}
|
|
|
|
func TestRuntimeImportServicePersistsPartialManagedResourcesOnAccessFailure(t *testing.T) {
|
|
store := openProvisionTestStore(t)
|
|
defer closeProvisionTestStore(t, store)
|
|
|
|
seedProvisionHost(t, store, "host-1", "https://sub2api.example.com")
|
|
|
|
host := &fakeHostAdapter{
|
|
batchAccounts: []sub2api.AccountRef{{ID: "account_1"}},
|
|
testResults: map[string]sub2api.ProbeResult{
|
|
"account_1": {OK: true, Status: "passed"},
|
|
},
|
|
models: map[string][]sub2api.AccountModel{
|
|
"account_1": {{ID: "deepseek-chat"}},
|
|
},
|
|
assignErr: fmt.Errorf("group is not a subscription type"),
|
|
}
|
|
|
|
svc := NewRuntimeImportService(store, host)
|
|
result, err := svc.Import(context.Background(), RuntimeImportRequest{
|
|
HostID: "host-1",
|
|
HostBaseURL: "https://sub2api.example.com",
|
|
Pack: pack.LoadedPack{
|
|
Manifest: pack.Manifest{PackID: "openai-cn-pack", Version: "1.0.0", TargetHost: "sub2api", MinHostVersion: "0.1.126", MaxHostVersion: "0.2.x"},
|
|
Checksum: "checksum-1",
|
|
},
|
|
Provider: sampleProviderManifest(),
|
|
Mode: ImportModePartial,
|
|
Keys: []string{"key-1"},
|
|
Access: AccessRequest{
|
|
Mode: AccessModeSubscription,
|
|
ProbeAPIKey: "user-key",
|
|
Subscriptions: []SubscriptionTarget{{UserID: "1", DurationDays: 30}},
|
|
},
|
|
})
|
|
if err == nil {
|
|
t.Fatal("RuntimeImportService.Import() error = nil, want partial failure")
|
|
}
|
|
if result.BatchID <= 0 {
|
|
t.Fatalf("BatchID = %d, want positive id", result.BatchID)
|
|
}
|
|
if got := queryCount(t, store.SQLDB(), "managed_resources"); got != 4 {
|
|
t.Fatalf("managed_resources row count = %d, want 4 persisted resources on partial failure", got)
|
|
}
|
|
var batchStatus string
|
|
if err := store.SQLDB().QueryRowContext(context.Background(), "SELECT batch_status FROM import_batches WHERE id = ?", result.BatchID).Scan(&batchStatus); err != nil {
|
|
t.Fatalf("query import batch status: %v", err)
|
|
}
|
|
if batchStatus != BatchStatusPartial {
|
|
t.Fatalf("persisted batch_status = %q, want %q", batchStatus, BatchStatusPartial)
|
|
}
|
|
}
|
|
|
|
func TestRuntimeImportServiceRepeatedImportReusesManagedResources(t *testing.T) {
|
|
store := openProvisionTestStore(t)
|
|
defer closeProvisionTestStore(t, store)
|
|
|
|
seedProvisionHost(t, store, "host-1", "https://sub2api.example.com")
|
|
|
|
host := &fakeHostAdapter{
|
|
batchAccounts: []sub2api.AccountRef{{ID: "account_1", Name: "key-1"}},
|
|
testResults: map[string]sub2api.ProbeResult{
|
|
"account_1": {OK: true, Status: "passed"},
|
|
},
|
|
models: map[string][]sub2api.AccountModel{
|
|
"account_1": {{ID: "deepseek-chat"}},
|
|
},
|
|
gatewayResult: sub2api.GatewayAccessResult{OK: true, StatusCode: 200, HasExpectedModel: true, Models: []string{"deepseek-chat"}},
|
|
}
|
|
|
|
svc := NewRuntimeImportService(store, host)
|
|
request := RuntimeImportRequest{
|
|
HostID: "host-1",
|
|
HostBaseURL: "https://sub2api.example.com",
|
|
Pack: pack.LoadedPack{
|
|
Manifest: pack.Manifest{PackID: "openai-cn-pack", Version: "1.0.0", TargetHost: "sub2api", MinHostVersion: "0.1.126", MaxHostVersion: "0.2.x"},
|
|
Checksum: "checksum-1",
|
|
},
|
|
Provider: sampleProviderManifest(),
|
|
Mode: ImportModePartial,
|
|
Keys: []string{"key-1"},
|
|
Access: AccessRequest{
|
|
Mode: AccessModeSelfService,
|
|
ProbeAPIKey: "user-key",
|
|
},
|
|
}
|
|
|
|
first, err := svc.Import(context.Background(), request)
|
|
if err != nil {
|
|
t.Fatalf("first Import() error = %v", err)
|
|
}
|
|
second, err := svc.Import(context.Background(), request)
|
|
if err != nil {
|
|
t.Fatalf("second Import() error = %v", err)
|
|
}
|
|
if second.BatchID <= first.BatchID {
|
|
t.Fatalf("second BatchID = %d, want > first BatchID %d", second.BatchID, first.BatchID)
|
|
}
|
|
if got := queryCount(t, store.SQLDB(), "managed_resources"); got != 3 {
|
|
t.Fatalf("managed_resources row count = %d, want 3 after reused import", got)
|
|
}
|
|
if got := queryCount(t, store.SQLDB(), "import_batches"); got != 2 {
|
|
t.Fatalf("import_batches row count = %d, want 2", got)
|
|
}
|
|
}
|
|
|
|
func TestRuntimeImportServiceImportReconcilesExistingChannelConfiguration(t *testing.T) {
|
|
store := openProvisionTestStore(t)
|
|
defer closeProvisionTestStore(t, store)
|
|
|
|
seedProvisionHost(t, store, "host-1", "https://sub2api.example.com")
|
|
|
|
host := &fakeHostAdapter{
|
|
batchAccounts: []sub2api.AccountRef{{ID: "account_1", Name: "minimax-01"}},
|
|
testResults: map[string]sub2api.ProbeResult{
|
|
"account_1": {OK: true, Status: "passed"},
|
|
},
|
|
models: map[string][]sub2api.AccountModel{
|
|
"account_1": {{ID: "MiniMax-M2.7-highspeed"}},
|
|
},
|
|
gatewayResult: sub2api.GatewayAccessResult{OK: true, StatusCode: 200, HasExpectedModel: true, Models: []string{"MiniMax-M2.5-highspeed", "MiniMax-M2.7-highspeed"}},
|
|
managedSnapshot: sub2api.ManagedResourceSnapshot{
|
|
Groups: []sub2api.NamedResource{{ID: "group_existing", Name: "MiniMax 默认分组-self-service"}},
|
|
Channels: []sub2api.NamedResource{{ID: "channel_existing", Name: "MiniMax 默认渠道-self-service"}},
|
|
Plans: []sub2api.NamedResource{{ID: "plan_existing", Name: "MiniMax 默认套餐-self-service"}},
|
|
},
|
|
}
|
|
|
|
provider := sampleProviderManifest()
|
|
provider.ProviderID = "minimax"
|
|
provider.DisplayName = "MiniMax OpenAI Compatible"
|
|
provider.BaseURL = "https://v2.aicodee.com/v1"
|
|
provider.DefaultModels = []string{"MiniMax-M2.5-highspeed", "MiniMax-M2.7-highspeed"}
|
|
provider.SmokeTestModel = "MiniMax-M2.7-highspeed"
|
|
provider.GroupTemplate.Name = "MiniMax 默认分组"
|
|
provider.ChannelTemplate = pack.ChannelTemplate{
|
|
Name: "MiniMax 默认渠道",
|
|
ModelMapping: map[string]string{"MiniMax-M2.5-highspeed": "MiniMax-M2.5-highspeed", "MiniMax-M2.7-highspeed": "MiniMax-M2.7-highspeed"},
|
|
}
|
|
provider.PlanTemplate.Name = "MiniMax 默认套餐"
|
|
|
|
svc := NewRuntimeImportService(store, host)
|
|
result, err := svc.Import(context.Background(), RuntimeImportRequest{
|
|
HostID: "host-1",
|
|
HostBaseURL: "https://sub2api.example.com",
|
|
Pack: pack.LoadedPack{
|
|
Manifest: pack.Manifest{PackID: "openai-cn-pack", Version: "1.0.0", TargetHost: "sub2api", MinHostVersion: "0.1.126", MaxHostVersion: "0.2.x"},
|
|
Checksum: "checksum-1",
|
|
},
|
|
Provider: provider,
|
|
Mode: ImportModePartial,
|
|
Keys: []string{"key-1"},
|
|
Access: AccessRequest{
|
|
Mode: AccessModeSelfService,
|
|
ProbeAPIKey: "user-key",
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("RuntimeImportService.Import() error = %v", err)
|
|
}
|
|
if result.Report.Channel.ID != "channel_existing" {
|
|
t.Fatalf("Channel.ID = %q, want reused channel_existing", result.Report.Channel.ID)
|
|
}
|
|
if host.createChannelCalls != 0 {
|
|
t.Fatalf("CreateChannel() calls = %d, want 0 when channel already exists", host.createChannelCalls)
|
|
}
|
|
if host.updateChannelCalls != 1 {
|
|
t.Fatalf("UpdateChannel() calls = %d, want 1", host.updateChannelCalls)
|
|
}
|
|
if host.updateChannelID != "channel_existing" {
|
|
t.Fatalf("UpdateChannel() id = %q, want channel_existing", host.updateChannelID)
|
|
}
|
|
if len(host.updateChannelReq.ModelPricing) != 1 {
|
|
t.Fatalf("UpdateChannel().ModelPricing len = %d, want 1", len(host.updateChannelReq.ModelPricing))
|
|
}
|
|
if got := host.updateChannelReq.ModelPricing[0].Models; len(got) != 2 || got[0] != "MiniMax-M2.5-highspeed" || got[1] != "MiniMax-M2.7-highspeed" {
|
|
t.Fatalf("UpdateChannel().ModelPricing[0].Models = %v, want minimax default models", got)
|
|
}
|
|
if host.updateChannelReq.ModelPricing[0].BillingMode != "token" {
|
|
t.Fatalf("UpdateChannel().ModelPricing[0].BillingMode = %q, want token", host.updateChannelReq.ModelPricing[0].BillingMode)
|
|
}
|
|
}
|
|
|
|
func openProvisionTestStore(t *testing.T) *sqlite.DB {
|
|
t.Helper()
|
|
|
|
dbPath := filepath.Join(t.TempDir(), "state.db")
|
|
dsn := fmt.Sprintf("file:%s?_busy_timeout=5000&_pragma=foreign_keys(0)", filepath.ToSlash(dbPath))
|
|
store, err := sqlite.Open(context.Background(), dsn)
|
|
if err != nil {
|
|
t.Fatalf("sqlite.Open() error = %v", err)
|
|
}
|
|
return store
|
|
}
|
|
|
|
func closeProvisionTestStore(t *testing.T, store *sqlite.DB) {
|
|
t.Helper()
|
|
if err := store.Close(); err != nil {
|
|
t.Fatalf("store.Close() error = %v", err)
|
|
}
|
|
}
|
|
|
|
func seedProvisionHost(t *testing.T, store *sqlite.DB, hostID, baseURL string) int64 {
|
|
t.Helper()
|
|
id, err := store.Hosts().Create(context.Background(), sqlite.Host{
|
|
HostID: hostID,
|
|
BaseURL: baseURL,
|
|
HostVersion: "0.1.126",
|
|
AuthType: "apikey",
|
|
AuthToken: "test-host-token",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Hosts().Create() error = %v", err)
|
|
}
|
|
return id
|
|
}
|
|
|
|
func queryCount(t *testing.T, db *sql.DB, table string) int {
|
|
t.Helper()
|
|
var count int
|
|
if err := db.QueryRowContext(context.Background(), "SELECT COUNT(*) FROM "+table).Scan(&count); err != nil {
|
|
t.Fatalf("count rows for %s: %v", table, err)
|
|
}
|
|
return count
|
|
}
|