This commit is contained in:
112
packages/server/tests/tools-routes.test.ts
Normal file
112
packages/server/tests/tools-routes.test.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* AI-OS Phase 0 — integration test for the tool-detection route.
|
||||
*
|
||||
* Boots a real local server (with the same fixture pattern used by
|
||||
* cross-platform.test.ts) and hits GET /api/tools/detect end-to-end.
|
||||
*
|
||||
* The detector itself is exhaustively unit-tested with injected deps
|
||||
* in `packages/agent/tests/tool-detection.test.ts`. This test verifies
|
||||
* that:
|
||||
* 1. The route is wired into the local server.
|
||||
* 2. The response envelope shape matches the shared contract.
|
||||
* 3. Every SUPPORTED_TOOLS id appears in the response.
|
||||
*
|
||||
* We deliberately do NOT assert on specific tool installation state
|
||||
* — that depends on the host machine running the tests and would
|
||||
* make the suite non-hermetic. We also do not assert on auth
|
||||
* rejection: the local sidecar is loopback-bound and intentionally
|
||||
* permits read-only in-process calls; tool detection reports only
|
||||
* what's already on the user's own machine and is not sensitive.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import os from 'node:os';
|
||||
import type { FastifyInstance } from 'fastify';
|
||||
import { MindDB, FrameStore, SessionStore } from '@waggle/core';
|
||||
import { SUPPORTED_TOOLS } from '@waggle/shared';
|
||||
import { buildLocalServer } from '../src/local/index.js';
|
||||
import { injectWithAuth } from './test-utils.js';
|
||||
|
||||
function createTmpDir(prefix: string): string {
|
||||
return fs.mkdtempSync(path.join(os.tmpdir(), `waggle-tools-${prefix}-`));
|
||||
}
|
||||
|
||||
function cleanupDir(dir: string): void {
|
||||
try {
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
} catch {
|
||||
/* best-effort */
|
||||
}
|
||||
}
|
||||
|
||||
describe('GET /api/tools/detect', () => {
|
||||
let server: FastifyInstance;
|
||||
let tmpDir: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
tmpDir = createTmpDir('routes');
|
||||
const personalPath = path.join(tmpDir, 'personal.mind');
|
||||
const mind = new MindDB(personalPath);
|
||||
const sessions = new SessionStore(mind);
|
||||
const frames = new FrameStore(mind);
|
||||
const s = sessions.create('tools-routes-test');
|
||||
frames.createIFrame(s.gop_id, 'tools-routes-test seed frame', 'normal');
|
||||
mind.close();
|
||||
|
||||
server = await buildLocalServer({ dataDir: tmpDir });
|
||||
await server.ready();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
if (server) await server.close();
|
||||
if (tmpDir) cleanupDir(tmpDir);
|
||||
});
|
||||
|
||||
it('returns 200 with a stable envelope shape', async () => {
|
||||
const res = await injectWithAuth(server, {
|
||||
method: 'GET',
|
||||
url: '/api/tools/detect',
|
||||
});
|
||||
expect(res.statusCode).toBe(200);
|
||||
const body = res.json();
|
||||
expect(body).toHaveProperty('platform');
|
||||
expect(body).toHaveProperty('detectedAt');
|
||||
expect(body).toHaveProperty('tools');
|
||||
expect(Array.isArray(body.tools)).toBe(true);
|
||||
});
|
||||
|
||||
it('covers every supported tool id in the envelope', async () => {
|
||||
const res = await injectWithAuth(server, {
|
||||
method: 'GET',
|
||||
url: '/api/tools/detect',
|
||||
});
|
||||
expect(res.statusCode).toBe(200);
|
||||
const body = res.json();
|
||||
const ids = body.tools.map((t: { id: string }) => t.id);
|
||||
for (const id of SUPPORTED_TOOLS) {
|
||||
expect(ids).toContain(id);
|
||||
}
|
||||
});
|
||||
|
||||
it('each tool entry has the expected fields', async () => {
|
||||
const res = await injectWithAuth(server, {
|
||||
method: 'GET',
|
||||
url: '/api/tools/detect',
|
||||
});
|
||||
const body = res.json();
|
||||
for (const t of body.tools) {
|
||||
expect(t).toHaveProperty('id');
|
||||
expect(t).toHaveProperty('displayName');
|
||||
expect(t).toHaveProperty('installed');
|
||||
expect(t).toHaveProperty('installedPath');
|
||||
expect(t).toHaveProperty('version');
|
||||
expect(t).toHaveProperty('hooksInstalled');
|
||||
expect(t).toHaveProperty('hookPointerPath');
|
||||
expect(typeof t.installed).toBe('boolean');
|
||||
expect(typeof t.hooksInstalled).toBe('boolean');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user