Expand coverage for runtime and sqlite paths

This commit is contained in:
phamnazage-jpg
2026-05-23 10:55:57 +08:00
parent 2ad277743d
commit bcc67c4a8a
17 changed files with 3393 additions and 1 deletions

View File

@@ -8,6 +8,7 @@ import (
"testing"
"sub2api-cn-relay-manager/internal/host/sub2api"
"sub2api-cn-relay-manager/internal/pack"
"sub2api-cn-relay-manager/internal/store/sqlite"
)
@@ -382,6 +383,127 @@ func TestStoredResourcesForReconcileMergesCurrentBatchAndSharedScaffoldingOnly(t
}
}
func TestReconcileValidatesTopLevelRequest(t *testing.T) {
t.Parallel()
req := Request{}
if _, err := NewService(nil, &reconcileHostStub{}).Reconcile(context.Background(), req); err == nil || err.Error() != "store is required" {
t.Fatalf("Reconcile(nil store) error = %v, want store is required", err)
}
store := openReconcileTestStore(t)
defer closeReconcileTestStore(t, store)
if _, err := NewService(store, nil).Reconcile(context.Background(), req); err == nil || err.Error() != "host adapter is required" {
t.Fatalf("Reconcile(nil host) error = %v, want host adapter is required", err)
}
if _, err := NewService(store, &reconcileHostStub{}).Reconcile(context.Background(), req); err == nil || err.Error() != "host_id is required" {
t.Fatalf("Reconcile(missing host_id) error = %v, want host_id is required", err)
}
if _, err := NewService(store, &reconcileHostStub{}).Reconcile(context.Background(), Request{HostID: "host-1"}); err == nil || err.Error() != "host_base_url is required" {
t.Fatalf("Reconcile(missing host_base_url) error = %v, want host_base_url is required", err)
}
}
func TestReconcileRejectsNonReconcilableLatestBatch(t *testing.T) {
t.Parallel()
store := openReconcileTestStore(t)
defer closeReconcileTestStore(t, store)
fixture := seedReconcileFixture(t, store)
mustExecReconcileSQL(t, store, `UPDATE import_batches SET batch_status = 'failed' WHERE id = ?`, fixture.batchID)
_, err := NewService(store, &reconcileHostStub{}).Reconcile(context.Background(), Request{
HostID: "host-1",
HostBaseURL: "https://sub2api.example.com",
AccessProbeAPIKey: "user-key",
Pack: pack.LoadedPack{
Manifest: pack.Manifest{PackID: "openai-cn-pack", Version: "1.0.0", TargetHost: "sub2api"},
},
Provider: pack.ProviderManifest{
ProviderID: "deepseek",
SmokeTestModel: "deepseek-chat",
},
})
if err == nil || err.Error() != "latest import batch is failed; run import again before reconcile" {
t.Fatalf("Reconcile() error = %v, want non-reconcilable batch error", err)
}
}
func TestReconcilePersistsActiveRunForHealthySnapshot(t *testing.T) {
t.Parallel()
store := openReconcileTestStore(t)
defer closeReconcileTestStore(t, store)
fixture := seedReconcileFixture(t, store)
mustCreateImportBatchItem(t, store, fixture.batchID, "fp-1", `{"account_id":"account-1"}`)
mustCreateManagedResource(t, store, fixture.batchID, fixture.hostPK, "group", "group-1", "group one")
mustCreateManagedResource(t, store, fixture.batchID, fixture.hostPK, "account", "account-1", "account one")
mustCreateAndLoadAccessClosures(t, store, fixture.batchID, sqlite.AccessClosureRecord{
BatchID: fixture.batchID,
ClosureType: accessModeSelfService,
Status: accessStatusSelfServiceReady,
})
host := &reconcileHostStub{
testResults: map[string]sub2api.ProbeResult{
"account-1": {OK: true, Status: accountStatusPassed, Message: "ok"},
},
models: map[string][]sub2api.AccountModel{
"account-1": {{ID: "deepseek-chat"}},
},
gatewayResult: sub2api.GatewayAccessResult{
OK: true,
StatusCode: 200,
HasExpectedModel: true,
CompletionOK: true,
Models: []string{"deepseek-chat"},
},
completionResults: []sub2api.GatewayCompletionResult{
{OK: true, StatusCode: 200},
},
managedResourceSnapshot: sub2api.ManagedResourceSnapshot{
Groups: []sub2api.NamedResource{{ID: "group-1", Name: "group one"}},
Accounts: []sub2api.NamedResource{{ID: "account-1", Name: "account one"}},
},
}
result, err := NewService(store, host).Reconcile(context.Background(), Request{
HostID: "host-1",
HostBaseURL: "https://sub2api.example.com",
AccessProbeAPIKey: "user-key",
Pack: pack.LoadedPack{
Manifest: pack.Manifest{PackID: "openai-cn-pack", Version: "1.0.0", TargetHost: "sub2api"},
},
Provider: pack.ProviderManifest{
ProviderID: "deepseek",
SmokeTestModel: "deepseek-chat",
},
})
if err != nil {
t.Fatalf("Reconcile() error = %v", err)
}
if result.Status != "active" {
t.Fatalf("result.Status = %q, want active", result.Status)
}
if result.MissingCount != 0 || result.ExtraCount != 0 || result.ProbeFailureCount != 0 {
t.Fatalf("result = %+v, want no drift and no probe failures", result)
}
if result.AccessStatus != accessStatusSelfServiceReady {
t.Fatalf("result.AccessStatus = %q, want %q", result.AccessStatus, accessStatusSelfServiceReady)
}
runs, err := store.ReconcileRuns().GetByBatchID(context.Background(), fixture.batchID)
if err != nil {
t.Fatalf("ReconcileRuns().GetByBatchID() error = %v", err)
}
if len(runs) != 1 || runs[0].Status != "active" {
t.Fatalf("persisted reconcile runs = %+v, want single active run", runs)
}
}
type reconcileFixture struct {
hostPK int64
packPK int64
@@ -512,6 +634,13 @@ func mustCreateAndLoadAccessClosures(t *testing.T, store *sqlite.DB, batchID int
return loaded
}
func mustExecReconcileSQL(t *testing.T, store *sqlite.DB, query string, args ...any) {
t.Helper()
if _, err := store.SQLDB().Exec(query, args...); err != nil {
t.Fatalf("Exec(%q) error = %v", query, err)
}
}
type reconcileHostStub struct {
disableResponsesErr error
gatewayErr error
@@ -525,6 +654,8 @@ type reconcileHostStub struct {
completionCalls int
disableResponsesCalls int
disabledResponsesAccounts []string
managedResourceSnapshot sub2api.ManagedResourceSnapshot
listManagedResourcesErr error
}
func (h *reconcileHostStub) GetHostVersion(context.Context) (string, error) {
@@ -632,5 +763,8 @@ func (h *reconcileHostStub) DisableOpenAIResponsesAPI(_ context.Context, account
}
func (h *reconcileHostStub) ListManagedResources(context.Context, sub2api.ListManagedResourcesRequest) (sub2api.ManagedResourceSnapshot, error) {
return sub2api.ManagedResourceSnapshot{}, nil
if h.listManagedResourcesErr != nil {
return sub2api.ManagedResourceSnapshot{}, h.listManagedResourcesErr
}
return h.managedResourceSnapshot, nil
}