import assert from 'node:assert/strict'; import test from 'node:test'; import { createAssetGatewayConfigService } from './asset-gateway.mjs'; function createPool() { let global = null; const plugins = new Map(); return { async query(sql, params = []) { const compact = sql.replace(/\s+/g, ' ').trim(); if (compact.startsWith('SELECT * FROM h5_asset_gateway_config')) return [[global].filter(Boolean)]; if (compact === 'SELECT * FROM h5_asset_plugin_configs ORDER BY plugin_id') { return [[...plugins.values()].sort((a, b) => a.plugin_id.localeCompare(b.plugin_id))]; } if (compact.startsWith('SELECT * FROM h5_asset_plugin_configs WHERE plugin_id')) { return [[plugins.get(params[0])].filter(Boolean)]; } if (compact.startsWith('INSERT INTO h5_asset_gateway_config')) { global = { config_key: params[0], enabled: params[1], updated_by: params[2], updated_at: params[3] }; return [{}]; } if (compact.startsWith('UPDATE h5_asset_gateway_config')) { global = { ...global, enabled: params[0], updated_by: params[1], updated_at: params[2] }; return [{}]; } if (compact.startsWith('INSERT INTO h5_asset_plugin_configs')) { plugins.set(params[1], { id: params[0], plugin_id: params[1], enabled: params[2], provider: params[3], llm_provider_key_id: params[4], llm_model: params[5], updated_by: params[6], created_at: params[7], updated_at: params[8], }); return [{}]; } if (compact.startsWith('UPDATE h5_asset_plugin_configs')) { const pluginId = params[6]; plugins.set(pluginId, { ...plugins.get(pluginId), enabled: params[0], provider: params[1], llm_provider_key_id: params[2], llm_model: params[3], updated_by: params[4], updated_at: params[5], }); return [{}]; } throw new Error(`Unexpected SQL: ${compact}`); }, }; } const llmProviderService = { async listKeys() { return [{ id: 'provider-key-1', name: 'Primary', providerId: 'custom', status: 'active', models: ['fast-model'], }]; }, }; test('asset gateway stays disabled by default and never blocks callers that choose to fall back', async () => { const service = createAssetGatewayConfigService(createPool(), { llmProviderService }); const config = await service.getConfig(); assert.equal(config.enabled, false); assert.equal(config.plugins.length, 4); assert.deepEqual(await service.resolvePlugin('asset-generate'), { ok: false, code: 'gateway_disabled', message: '资产能力未启用,可安全降级到原有流程', }); }); test('each optional asset plugin can bind its own approved LLM model', async () => { const service = createAssetGatewayConfigService(createPool(), { llmProviderService }); await service.updateGlobalConfig({ enabled: true }, { updatedBy: 'admin-1' }); const result = await service.updatePluginConfig('asset-generate', { enabled: true, provider: 'flux-schnell', llmProviderKeyId: 'provider-key-1', llmModel: 'fast-model', }, { updatedBy: 'admin-1' }); assert.equal(result.ok, true); const plugin = result.config.plugins.find((item) => item.pluginId === 'asset-generate'); assert.equal(plugin.enabled, true); assert.equal(plugin.provider, 'flux-schnell'); assert.equal(plugin.llmModel, 'fast-model'); assert.equal((await service.resolvePlugin('asset-generate')).ok, true); }); test('asset plugins reject unknown providers and unsupported LLM bindings', async () => { const service = createAssetGatewayConfigService(createPool(), { llmProviderService }); const invalidProvider = await service.updatePluginConfig('asset-generate', { enabled: true, provider: 'unknown-provider', }); assert.equal(invalidProvider.ok, false); assert.match(invalidProvider.message, /Provider/); const unsupportedLlm = await service.updatePluginConfig('asset-transform', { enabled: true, provider: 'sharp', llmProviderKeyId: 'provider-key-1', llmModel: 'fast-model', }); assert.equal(unsupportedLlm.ok, false); assert.match(unsupportedLlm.message, /不支持 LLM/); });