import { RuntimeInternalController } from './runtime-internal.controller'; describe('RuntimeInternalController', () => { let controller: RuntimeInternalController; let mockService: any; beforeEach(() => { mockService = { pollJobs: jest.fn(), lockJob: jest.fn(), heartbeatJob: jest.fn(), getSnapshot: jest.fn(), resolveCredential: jest.fn(), submitResult: jest.fn(), submitFailure: jest.fn(), submitInvocationLogs: jest.fn(), }; controller = new RuntimeInternalController(mockService); }); const req = (instanceId?: string) => ({ headers: { 'x-runtime-instance-id': instanceId } }) as any; // ═══════════════════════════════════════════════════════════════════ // instanceId extraction // ═══════════════════════════════════════════════════════════════════ describe('instanceId extraction', () => { it('extracts x-runtime-instance-id from header', async () => { const dto = { supportedJobTypes: ['quiz_generation'], limit: 10, capabilities: {} }; mockService.pollJobs.mockResolvedValue({ jobs: [] }); await controller.pollJobs(req('rt-001'), dto as any); expect(mockService.pollJobs).toHaveBeenCalledWith( 'rt-001', ['quiz_generation'], 10, {}, ); }); it('falls back to "unknown" when header is missing', async () => { const dto = { supportedJobTypes: ['quiz_generation'] }; mockService.pollJobs.mockResolvedValue({ jobs: [] }); await controller.pollJobs(req(undefined), dto as any); expect(mockService.pollJobs).toHaveBeenCalledWith( 'unknown', ['quiz_generation'], 5, undefined, ); }); }); // ═══════════════════════════════════════════════════════════════════ // Poll // ═══════════════════════════════════════════════════════════════════ describe('pollJobs', () => { it('delegates with defaults (limit=5 when undefined)', async () => { const dto = { supportedJobTypes: ['learning_state_analysis'], limit: undefined }; mockService.pollJobs.mockResolvedValue({ jobs: [] }); await controller.pollJobs(req('rt-1'), dto as any); expect(mockService.pollJobs).toHaveBeenCalledWith('rt-1', ['learning_state_analysis'], 5, undefined); }); }); // ═══════════════════════════════════════════════════════════════════ // Lock // ═══════════════════════════════════════════════════════════════════ describe('lockJob', () => { it('uses dto.runtimeInstanceId when provided', async () => { const dto = { runtimeInstanceId: 'rt-custom' }; mockService.lockJob.mockResolvedValue({ status: 'locked' }); await controller.lockJob(req('rt-head'), 'j1', dto); expect(mockService.lockJob).toHaveBeenCalledWith('j1', 'rt-custom'); }); it('falls back to header instanceId', async () => { const dto = { runtimeInstanceId: undefined as any }; mockService.lockJob.mockResolvedValue({ status: 'locked' }); await controller.lockJob(req('rt-head'), 'j1', dto); expect(mockService.lockJob).toHaveBeenCalledWith('j1', 'rt-head'); }); }); // ═══════════════════════════════════════════════════════════════════ // Heartbeat // ═══════════════════════════════════════════════════════════════════ describe('heartbeatJob', () => { it('delegates with instanceId fallback', async () => { const dto = { runtimeInstanceId: undefined as any }; mockService.heartbeatJob.mockResolvedValue({ lockUntil: 123, cancelRequested: false }); await controller.heartbeatJob(req('rt-hb'), 'j1', dto); expect(mockService.heartbeatJob).toHaveBeenCalledWith('j1', 'rt-hb'); }); }); // ═══════════════════════════════════════════════════════════════════ // Snapshot // ═══════════════════════════════════════════════════════════════════ describe('getSnapshot', () => { it('delegates to service.getSnapshot', async () => { mockService.getSnapshot.mockResolvedValue({ snapshotId: 's1' }); const result = await controller.getSnapshot('j1'); expect(mockService.getSnapshot).toHaveBeenCalledWith('j1'); expect(result).toEqual({ snapshotId: 's1' }); }); }); // ═══════════════════════════════════════════════════════════════════ // Credential Resolve // ═══════════════════════════════════════════════════════════════════ describe('resolveCredential', () => { it('delegates with all fields', async () => { const dto = { jobId: 'j1', apiKeyMode: 'user_deepseek_key', provider: 'deepseek', credentialId: 'c1' }; mockService.resolveCredential.mockResolvedValue({ apiKey: 'sk-xx' }); await controller.resolveCredential(dto as any); expect(mockService.resolveCredential).toHaveBeenCalledWith('j1', 'user_deepseek_key', 'deepseek', 'c1'); }); it('passes undefined credentialId when omitted', async () => { const dto = { jobId: 'j1', apiKeyMode: 'platform_key', provider: 'deepseek' }; mockService.resolveCredential.mockResolvedValue({ apiKey: '' }); await controller.resolveCredential(dto as any); expect(mockService.resolveCredential).toHaveBeenCalledWith('j1', 'platform_key', 'deepseek', undefined); }); }); // ═══════════════════════════════════════════════════════════════════ // Submit Result // ═══════════════════════════════════════════════════════════════════ describe('submitResult', () => { it('delegates entire dto to service', async () => { const dto = { runtimeInstanceId: 'rt-1', schemaVersion: 'v1', status: 'succeeded', attemptNo: 1 }; mockService.submitResult.mockResolvedValue({ status: 'ok' }); const result = await controller.submitResult('j1', dto as any); expect(mockService.submitResult).toHaveBeenCalledWith('j1', dto); expect(result).toEqual({ status: 'ok' }); }); }); // ═══════════════════════════════════════════════════════════════════ // Submit Failure // ═══════════════════════════════════════════════════════════════════ describe('submitFailure', () => { it('delegates entire dto to service', async () => { const dto = { runtimeInstanceId: 'rt-1', errorCode: 'ERR', errorMessage: 'msg', retryable: false }; mockService.submitFailure.mockResolvedValue({ status: 'failed' }); await controller.submitFailure('j1', dto as any); expect(mockService.submitFailure).toHaveBeenCalledWith('j1', dto); }); }); // ═══════════════════════════════════════════════════════════════════ // Submit Invocation Logs // ═══════════════════════════════════════════════════════════════════ describe('submitInvocationLogs', () => { it('extracts logs array from dto', async () => { const dto = { logs: [{ jobId: 'j1', provider: 'deepseek' }] }; mockService.submitInvocationLogs.mockResolvedValue({ accepted: 1 }); const result = await controller.submitInvocationLogs(dto as any); expect(mockService.submitInvocationLogs).toHaveBeenCalledWith(dto.logs); expect(result).toEqual({ accepted: 1 }); }); }); });