import { assertEquals, assertThrows } from '@std/assert'; import { AppStoreManager } from '../ts/classes/appstore.ts'; import { OneboxDockerManager } from '../ts/classes/docker.ts'; import type { IAppVersionConfig } from '../ts/classes/appstore-types.ts'; import type { IService } from '../ts/types.ts'; const createAppStore = () => new AppStoreManager({} as any); const baseConfig: IAppVersionConfig = { image: 'example/app:1.0.0', port: 3000, envVars: [ { key: 'APP_PORT', value: '3000', description: 'Application port', required: true, }, ], }; const baseService: IService = { id: 1, name: 'test-service', image: 'example/app:1.0.0', envVars: {}, port: 3000, status: 'stopped', createdAt: Date.now(), updatedAt: Date.now(), }; Deno.test('appstore normalizes and validates app template runtime fields', () => { const appStore = createAppStore(); const normalizedVolumes = appStore.normalizeVolumes([ '/data/app', { mountPath: '/config', readOnly: true }, ]); assertEquals(normalizedVolumes, [ { mountPath: '/data/app' }, { mountPath: '/config', readOnly: true }, ]); appStore.validateAppVersionConfig({ ...baseConfig, volumes: normalizedVolumes, publishedPorts: [ { targetPort: 3000, publishedPort: 3000, protocol: 'tcp' }, { targetPort: 20000, targetPortEnd: 20002, publishedPort: 20000, publishedPortEnd: 20002, protocol: 'udp' }, ], }); }); Deno.test('appstore rejects invalid template ports and volumes', () => { const appStore = createAppStore(); assertThrows( () => appStore.validateAppVersionConfig({ ...baseConfig, port: 70000 }), Error, 'Invalid app config port', ); assertThrows( () => appStore.normalizeVolumes([{ mountPath: 'relative/path' }]), Error, 'mountPath must be an absolute path', ); assertThrows( () => appStore.validateAppVersionConfig({ ...baseConfig, publishedPorts: [ { targetPort: 3000, targetPortEnd: 3002, publishedPort: 3000, publishedPortEnd: 3001, protocol: 'tcp' }, ], }), Error, 'ranges must have the same size', ); }); Deno.test('docker service spec validation rejects unsafe volume and port declarations', () => { const dockerManager = new OneboxDockerManager(); dockerManager.validateServiceSpec({ ...baseService, volumes: [{ mountPath: '/data/app' }], publishedPorts: [{ targetPort: 3000, publishedPort: 3000, protocol: 'tcp' }], }); assertThrows( () => dockerManager.validateServiceSpec({ ...baseService, volumes: [{ mountPath: 'relative/path' }], }), Error, 'must be an absolute path', ); assertThrows( () => dockerManager.validateServiceSpec({ ...baseService, publishedPorts: [ { targetPort: 3001, publishedPort: 3000, hostIp: '127.0.0.1', protocol: 'tcp' }, { targetPort: 3000, publishedPort: 3000, protocol: 'tcp' }, ], }), Error, 'Duplicate published port', ); });