import { describe, expect, test, vi } from 'vitest'; import { createAgcDevEndpoint, resolveAgcDevEndpoint, withAgcDevEndpointEnv, } from '../scripts/dev-port.mjs'; describe('AI 游戏创作 dev 端口', () => { test('Linux 使用用户端口段的 start + 5 槽位', async () => { const findPort = vi.fn(async ({ preferredPort }) => preferredPort); const endpoint = await resolveAgcDevEndpoint({ env: { USER: 'alice', LOGNAME: 'alice' }, platform: 'linux', reservePortRange: async () => ({ username: 'alice', range: { start: 10000, end: 10099, label: '10000-10099' }, }), findPort, }); expect(endpoint).toMatchObject({ port: 10005, url: 'http://127.0.0.1:10005/', markerUrl: 'http://127.0.0.1:10005/__agc_dev_server.json', }); expect(findPort).toHaveBeenCalledWith( expect.objectContaining({ preferredPort: 10005, portRange: { start: 10000, end: 10099, label: '10000-10099' }, strict: false, }), ); }); test('Linux 槽位被占时接受本用户端口段内的漂移结果', async () => { const endpoint = await resolveAgcDevEndpoint({ env: { USER: 'alice', LOGNAME: 'alice' }, platform: 'linux', reservePortRange: async () => ({ username: 'alice', range: { start: 10000, end: 10099, label: '10000-10099' }, }), findPort: async ({ preferredPort, portRange }) => { expect(preferredPort).toBe(10005); expect(portRange?.label).toBe('10000-10099'); return 10006; }, }); expect(endpoint.port).toBe(10006); }); test('父启动器选定端口后子启动器严格使用同一端口', async () => { const findPort = vi.fn(async ({ preferredPort }) => preferredPort); await resolveAgcDevEndpoint({ env: { USER: 'alice', LOGNAME: 'alice', GENARRATIVE_AGC_VITE_PORT: '10007', }, platform: 'linux', strictConfigured: true, reservePortRange: async () => ({ username: 'alice', range: { start: 10000, end: 10099, label: '10000-10099' }, }), findPort, }); expect(findPort).toHaveBeenCalledWith( expect.objectContaining({ preferredPort: 10007, strict: true }), ); }); test('旧五端口段无法安全扩容时 AGC 明确失败而不越界', async () => { await expect( resolveAgcDevEndpoint({ env: { USER: 'alice', LOGNAME: 'alice' }, platform: 'linux', reservePortRange: async () => ({ username: 'alice', range: { start: 10000, end: 10004, label: '10000-10004' }, }), findPort: async () => 10005, }), ).rejects.toThrow('缺少 AGC Vite 槽位'); }); test('Linux 显式 AGC 端口不能占用前五个服务槽位', async () => { await expect( resolveAgcDevEndpoint({ env: { USER: 'alice', LOGNAME: 'alice', GENARRATIVE_AGC_VITE_PORT: '10004', }, platform: 'linux', reservePortRange: async () => ({ username: 'alice', range: { start: 10000, end: 10099, label: '10000-10099' }, }), findPort: async () => 10004, }), ).rejects.toThrow('前五个服务槽位'); }); test('非 Linux 保留 3080 兼容优先端口并允许统一漂移', async () => { const findPort = vi.fn(async () => 3081); const endpoint = await resolveAgcDevEndpoint({ env: {}, platform: 'win32', findPort, }); expect(endpoint.port).toBe(3081); expect(findPort).toHaveBeenCalledWith( expect.objectContaining({ preferredPort: 3080, portRange: null }), ); }); test('最终端口通过单一环境变量传给 Tauri 和 Vite 子进程', () => { expect( withAgcDevEndpointEnv(createAgcDevEndpoint(10008), { KEEP_ME: 'yes' }), ).toMatchObject({ KEEP_ME: 'yes', GENARRATIVE_AGC_VITE_PORT: '10008', }); }); });