test: cover model refresh early returns

This commit is contained in:
cita
2026-03-10 16:12:38 +08:00
parent e1b4452c82
commit d5cd8292eb
2 changed files with 116 additions and 10 deletions
@@ -80,6 +80,8 @@ describe('refreshModelsForAccount credential discovery', () => {
accountId: account.id,
refreshed: true,
status: 'success',
errorCode: null,
errorMessage: '',
modelCount: 2,
modelsPreview: ['claude-sonnet-4-5-20250929', 'claude-opus-4-6'],
tokenScanned: 0,
@@ -139,4 +141,79 @@ describe('refreshModelsForAccount credential discovery', () => {
expect(parsed.runtimeHealth?.reason).toBe('模型获取失败,API Key 已无效');
expect(parsed.runtimeHealth?.checkedAt).toMatch(/\d{4}-\d{2}-\d{2}T/);
});
it('returns structured result when account missing', async () => {
const result = await refreshModelsForAccount(9999);
expect(result).toMatchObject({
accountId: 9999,
refreshed: false,
status: 'failed',
errorCode: 'account_not_found',
errorMessage: '账号不存在',
modelCount: 0,
modelsPreview: [],
reason: 'account_not_found',
});
});
it('returns structured result when site disabled', async () => {
const site = await db.insert(schema.sites).values({
name: 'site-disabled',
url: 'https://site-disabled.example.com',
platform: 'new-api',
status: 'disabled',
}).returning().get();
const account = await db.insert(schema.accounts).values({
siteId: site.id,
username: 'disabled-user',
accessToken: 'session-token',
apiToken: null,
status: 'active',
}).returning().get();
const result = await refreshModelsForAccount(account.id);
expect(result).toMatchObject({
accountId: account.id,
refreshed: false,
status: 'skipped',
errorCode: 'site_disabled',
errorMessage: '站点已禁用',
modelCount: 0,
modelsPreview: [],
reason: 'site_disabled',
});
});
it('returns structured result when account inactive', async () => {
const site = await db.insert(schema.sites).values({
name: 'site-inactive',
url: 'https://site-inactive.example.com',
platform: 'new-api',
status: 'active',
}).returning().get();
const account = await db.insert(schema.accounts).values({
siteId: site.id,
username: 'inactive-user',
accessToken: 'session-token',
apiToken: null,
status: 'disabled',
}).returning().get();
const result = await refreshModelsForAccount(account.id);
expect(result).toMatchObject({
accountId: account.id,
refreshed: false,
status: 'skipped',
errorCode: 'adapter_or_status',
errorMessage: '平台不可用或账号未激活',
modelCount: 0,
modelsPreview: [],
reason: 'adapter_or_status',
});
});
});
+32 -3
View File
@@ -71,7 +71,16 @@ export async function refreshModelsForAccount(accountId: number) {
.get();
if (!row) {
return { accountId, refreshed: false, modelCount: 0, reason: 'account_not_found' };
return {
accountId,
refreshed: false,
status: 'failed',
errorCode: 'account_not_found',
errorMessage: '账号不存在',
modelCount: 0,
modelsPreview: [],
reason: 'account_not_found',
};
}
const account = row.accounts;
@@ -94,11 +103,29 @@ export async function refreshModelsForAccount(accountId: number) {
}
if (isSiteDisabled(site.status)) {
return { accountId, refreshed: false, modelCount: 0, reason: 'site_disabled' };
return {
accountId,
refreshed: false,
status: 'skipped',
errorCode: 'site_disabled',
errorMessage: '站点已禁用',
modelCount: 0,
modelsPreview: [],
reason: 'site_disabled',
};
}
if (!adapter || account.status !== 'active') {
return { accountId, refreshed: false, modelCount: 0, reason: 'adapter_or_status' };
return {
accountId,
refreshed: false,
status: 'skipped',
errorCode: 'adapter_or_status',
errorMessage: '平台不可用或账号未激活',
modelCount: 0,
modelsPreview: [],
reason: 'adapter_or_status',
};
}
const platformUserId = resolvePlatformUserId(account.extraConfig, account.username);
@@ -278,6 +305,8 @@ export async function refreshModelsForAccount(accountId: number) {
accountId,
refreshed: true,
status: 'success',
errorCode: null,
errorMessage: '',
modelCount: accountModels.size,
modelsPreview,
tokenScanned: scannedTokenCount,