CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes48downloads
cron-create.test.ts182 linesDownload Raw Back to tools
1import * as fs from 'node:fs/promises';2import * as os from 'node:os';3import * as path from 'node:path';4import { afterEach, beforeEach, describe, expect, it } from 'vitest';5import { CronCreateTool } from './cron-create.js';6import { CronScheduler } from '../services/cronScheduler.js';7import { readCronTasks } from '../services/cronTasksFile.js';8import { Storage } from '../config/storage.js';9 10let tmpDir: string;11 12function makeConfig(maxAgeDays = 7) {13  const scheduler = new CronScheduler(tmpDir, maxAgeDays * 24 * 60 * 60 * 1000);14  return {15    getCronScheduler: () => scheduler,16    getCronRecurringMaxAgeDays: () => maxAgeDays,17    getProjectRoot: () => tmpDir,18    _scheduler: scheduler,19  } as unknown as import('../config/config.js').Config & {20    _scheduler: CronScheduler;21  };22}23 24describe('CronCreateTool', () => {25  let config: ReturnType<typeof makeConfig>;26  let tool: CronCreateTool;27 28  beforeEach(async () => {29    tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'cron-create-test-'));30    // Durable tasks persist under the user runtime dir, not the tree.31    Storage.setRuntimeBaseDir(tmpDir);32    config = makeConfig();33    tool = new CronCreateTool(config);34  });35 36  afterEach(async () => {37    Storage.setRuntimeBaseDir(null);38    await fs.rm(tmpDir, { recursive: true, force: true });39  });40 41  it('has the correct name', () => {42    expect(tool.name).toBe('cron_create');43  });44 45  it('creates a recurring job by default', async () => {46    const invocation = tool.build({47      cron: '*/5 * * * *',48      prompt: 'check status',49    });50    const result = await invocation.execute(new AbortController().signal);51    expect(result.error).toBeUndefined();52    expect(result.llmContent).toContain('Scheduled recurring job');53    expect(result.llmContent).toContain('Auto-expires after 7 days');54    expect(result.llmContent).toContain('Session-only');55    expect(config._scheduler.list()).toHaveLength(1);56  });57 58  it('reports a configured recurring max age in days', async () => {59    config = makeConfig(30);60    tool = new CronCreateTool(config);61    const invocation = tool.build({62      cron: '*/5 * * * *',63      prompt: 'check status',64    });65    const result = await invocation.execute(new AbortController().signal);66    expect(result.error).toBeUndefined();67    expect(result.llmContent).toContain('Auto-expires after 30 days');68    expect(tool.description).toContain('auto-expire after 30 days');69  });70 71  it('reports no expiry when the recurring max age is disabled', async () => {72    config = makeConfig(Infinity);73    tool = new CronCreateTool(config);74    const invocation = tool.build({75      cron: '*/5 * * * *',76      prompt: 'check status',77    });78    const result = await invocation.execute(new AbortController().signal);79    expect(result.error).toBeUndefined();80    expect(result.llmContent).toContain('Never auto-expires');81    expect(tool.description).toContain('never auto-expire');82    const job = config._scheduler.list()[0]!;83    expect(job.expiresAt).toBe(Infinity);84  });85 86  it('creates a one-shot job when recurring=false', async () => {87    const invocation = tool.build({88      cron: '*/1 * * * *',89      prompt: 'once',90      recurring: false,91    });92    const result = await invocation.execute(new AbortController().signal);93    expect(result.error).toBeUndefined();94    expect(result.llmContent).toContain('Scheduled one-shot task');95    expect(result.llmContent).toContain('fire once then auto-delete');96    const jobs = config._scheduler.list();97    expect(jobs).toHaveLength(1);98    expect(jobs[0]!.recurring).toBe(false);99  });100 101  it('creates a durable job and writes to disk', async () => {102    const invocation = tool.build({103      cron: '*/5 * * * *',104      prompt: 'durable check',105      durable: true,106    });107    const result = await invocation.execute(new AbortController().signal);108    expect(result.error).toBeUndefined();109    expect(result.llmContent).toContain(110      'Persisted to ~/.qwen/tmp/<project-hash>/scheduled_tasks.json',111    );112    expect(result.returnDisplay).toContain('[durable]');113 114    // Verify file was written115    const tasks = await readCronTasks(tmpDir);116    expect(tasks).toHaveLength(1);117    expect(tasks[0]!.prompt).toBe('durable check');118  });119 120  it('does not write to disk when durable=false', async () => {121    const invocation = tool.build({122      cron: '*/5 * * * *',123      prompt: 'session only',124    });125    await invocation.execute(new AbortController().signal);126 127    const tasks = await readCronTasks(tmpDir);128    expect(tasks).toHaveLength(0);129  });130 131  it.each(['', '   '])('rejects blank prompt %j', (prompt) => {132    expect(() =>133      tool.build({134        cron: '*/5 * * * *',135        prompt,136      }),137    ).toThrow('Parameter "prompt" must be a non-empty string.');138    expect(config._scheduler.list()).toHaveLength(0);139  });140 141  it('trims the prompt before scheduling the job', async () => {142    const invocation = tool.build({143      cron: '*/5 * * * *',144      prompt: '  check status  ',145    });146 147    const result = await invocation.execute(new AbortController().signal);148 149    expect(result.error).toBeUndefined();150    const jobs = config._scheduler.list();151    expect(jobs).toHaveLength(1);152    expect(jobs[0]!.prompt).toBe('check status');153  });154 155  it('returns error for invalid cron expression', async () => {156    const invocation = tool.build({157      cron: 'bad cron',158      prompt: 'fail',159    });160    const result = await invocation.execute(new AbortController().signal);161    expect(result.error).toBeDefined();162  });163 164  it('rejects a cron that never matches a real date', async () => {165    // Parses fine, but Feb 30 never exists — accepting it would166    // schedule a job that silently never fires.167    const invocation = tool.build({168      cron: '0 0 30 2 *',169      prompt: 'never fires',170    });171    const result = await invocation.execute(new AbortController().signal);172    expect(result.error).toBeDefined();173    expect(result.llmContent).toContain('No matching fire time');174    expect(config._scheduler.list()).toHaveLength(0);175  });176 177  it('validates required params', () => {178    expect(() => tool.build({ cron: '*/1 * * * *' } as never)).toThrow();179    expect(() => tool.build({ prompt: 'test' } as never)).toThrow();180  });181});182 
basant307/AI_Governance_Project · CoolFace