CoolFace
Apppublic

Leon4gr45/builder

sourceHugging Facemitupdated 2d agoView on Hugging Face
0likes
task-manager.test.ts119 linesDownload Raw Back to __tests__
1import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';2import { TaskManager } from '../task-manager';3 4describe('TaskManager', () => {5  let tm: TaskManager;6 7  beforeEach(() => {8    tm = new TaskManager({ maxConcurrentPerScope: 3, keyTTLMs: 30 * 60 * 1000 });9  });10 11  afterEach(() => {12    tm.dispose();13  });14 15  it('creates a task and returns taskId', () => {16    const taskId = tm.createTask('proj-1', 'session-1', 'sk-key', 'workspace-1');17    expect(taskId).toBeDefined();18    expect(typeof taskId).toBe('string');19  });20 21  it('retrieves a created task', () => {22    const taskId = tm.createTask('proj-1', 'session-1', 'sk-key');23    const task = tm.getTask(taskId);24    expect(task).toBeDefined();25    expect(task!.projectId).toBe('proj-1');26    expect(task!.status).toBe('running');27  });28 29  it('returns undefined for unknown taskId', () => {30    expect(tm.getTask('nonexistent')).toBeUndefined();31  });32 33  it('stores and retrieves API key', () => {34    const taskId = tm.createTask('proj-1', 'session-1', 'sk-secret');35    expect(tm.getApiKey(taskId)).toBe('sk-secret');36  });37 38  it('deletes API key on task completion', () => {39    const taskId = tm.createTask('proj-1', 'session-1', 'sk-secret');40    tm.completeTask(taskId, 'completed');41    expect(tm.getApiKey(taskId)).toBeUndefined();42  });43 44  it('deletes API key on task failure', () => {45    const taskId = tm.createTask('proj-1', 'session-1', 'sk-secret');46    tm.completeTask(taskId, 'failed');47    expect(tm.getApiKey(taskId)).toBeUndefined();48  });49 50  it('deletes API key on task cancellation', () => {51    const taskId = tm.createTask('proj-1', 'session-1', 'sk-secret');52    tm.completeTask(taskId, 'cancelled');53    expect(tm.getApiKey(taskId)).toBeUndefined();54  });55 56  it('enforces concurrent task limit per workspace', () => {57    tm.createTask('proj-1', 'session-1', 'k1', 'ws-1');58    tm.createTask('proj-2', 'session-1', 'k2', 'ws-1');59    tm.createTask('proj-3', 'session-1', 'k3', 'ws-1');60    expect(() => tm.createTask('proj-4', 'session-1', 'k4', 'ws-1')).toThrow(/concurrent task limit/i);61  });62 63  it('enforces concurrent task limit per session when no workspace', () => {64    tm.createTask('proj-1', 'sess-1', 'k1');65    tm.createTask('proj-2', 'sess-1', 'k2');66    tm.createTask('proj-3', 'sess-1', 'k3');67    expect(() => tm.createTask('proj-4', 'sess-1', 'k4')).toThrow(/concurrent task limit/i);68  });69 70  it('allows tasks from different scopes', () => {71    tm.createTask('proj-1', 'sess-1', 'k1', 'ws-1');72    tm.createTask('proj-2', 'sess-1', 'k2', 'ws-1');73    tm.createTask('proj-3', 'sess-1', 'k3', 'ws-1');74    const taskId = tm.createTask('proj-4', 'sess-1', 'k4', 'ws-2');75    expect(taskId).toBeDefined();76  });77 78  it('completed tasks free up slots', () => {79    const t1 = tm.createTask('proj-1', 'sess-1', 'k1', 'ws-1');80    tm.createTask('proj-2', 'sess-1', 'k2', 'ws-1');81    tm.createTask('proj-3', 'sess-1', 'k3', 'ws-1');82    tm.completeTask(t1, 'completed');83    const t4 = tm.createTask('proj-4', 'sess-1', 'k4', 'ws-1');84    expect(t4).toBeDefined();85  });86 87  it('getTasksForSession returns all tasks for a session', () => {88    tm.createTask('proj-1', 'sess-1', 'k1');89    tm.createTask('proj-2', 'sess-1', 'k2');90    tm.createTask('proj-3', 'sess-2', 'k3');91    expect(tm.getTasksForSession('sess-1')).toHaveLength(2);92    expect(tm.getTasksForSession('sess-2')).toHaveLength(1);93  });94 95  it('stores metadata (prompt, model, projectName) on task', () => {96    const taskId = tm.createTask('proj-1', 'sess-1', 'sk-key');97    const task = tm.getTask(taskId)!;98    task.prompt = 'make a button';99    task.model = 'gpt-4o';100    task.projectName = 'My Project';101 102    const retrieved = tm.getTask(taskId)!;103    expect(retrieved.prompt).toBe('make a button');104    expect(retrieved.model).toBe('gpt-4o');105    expect(retrieved.projectName).toBe('My Project');106  });107 108  it('TTL sweep removes expired keys', () => {109    vi.useFakeTimers();110    const shortTTL = new TaskManager({ maxConcurrentPerScope: 3, keyTTLMs: 1000 });111    const taskId = shortTTL.createTask('proj-1', 'sess-1', 'sk-expire');112    vi.advanceTimersByTime(1500);113    shortTTL.sweepExpiredKeys();114    expect(shortTTL.getApiKey(taskId)).toBeUndefined();115    shortTTL.dispose();116    vi.useRealTimers();117  });118});119