moving
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled

This commit is contained in:
Oleg Maslov
2026-09-02 10:10:29 +02:00
commit 0c3e2ead3b
3841 changed files with 970576 additions and 0 deletions

View File

@@ -0,0 +1,150 @@
/**
* Embedding routing API tests (steal #10) —
* GET /api/embedding/status (enriched: configuredProvider + envOverride)
* POST /api/embedding/provider (validate → tier-gate → persist → restartRequired)
*
* Note: vitest.setup.ts pins EMBEDDING_PROVIDER='mock' for the whole suite, so the
* env-override branch would otherwise 409 every write. We clear it per-test to
* exercise the real paths, and set it explicitly for the override test.
*/
import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import { MindDB, SessionStore, FrameStore } from '@waggle/core';
import { buildLocalServer } from '../../src/local/index.js';
import type { FastifyInstance } from 'fastify';
import { injectWithAuth } from '../test-utils.js';
describe('Embedding routing API', () => {
let server: FastifyInstance;
let tmpDir: string;
const ORIGINAL_ENV = process.env.EMBEDDING_PROVIDER;
function readConfig(): Record<string, unknown> {
return JSON.parse(fs.readFileSync(path.join(tmpDir, 'config.json'), 'utf-8'));
}
beforeAll(async () => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'waggle-embrouting-test-'));
// No `tier` field → effective tier resolves to FREE (litellm gated off).
fs.writeFileSync(path.join(tmpDir, 'config.json'), JSON.stringify({}));
fs.mkdirSync(path.join(tmpDir, 'skills'), { recursive: true });
fs.writeFileSync(path.join(tmpDir, 'skills', '.starter-installed'), 'test');
const personalPath = path.join(tmpDir, 'personal.mind');
const mind = new MindDB(personalPath);
const sessions = new SessionStore(mind);
const frames = new FrameStore(mind);
const s1 = sessions.create('embrouting-test');
frames.createIFrame(s1.gop_id, 'Embedding routing test frame', 'normal');
mind.close();
server = await buildLocalServer({ dataDir: tmpDir });
});
afterAll(async () => {
await server.close();
fs.rmSync(tmpDir, { recursive: true, force: true });
if (ORIGINAL_ENV === undefined) delete process.env.EMBEDDING_PROVIDER;
else process.env.EMBEDDING_PROVIDER = ORIGINAL_ENV;
});
// Default to the no-env-override path; the override test opts back in.
beforeEach(() => { delete process.env.EMBEDDING_PROVIDER; });
it('GET /api/embedding/status returns the enriched shape', async () => {
const res = await injectWithAuth(server, { method: 'GET', url: '/api/embedding/status' });
expect(res.statusCode).toBe(200);
const body = JSON.parse(res.body);
expect(typeof body.activeProvider).toBe('string');
expect(Array.isArray(body.availableProviders)).toBe(true);
expect(typeof body.dimensions).toBe('number');
expect(typeof body.modelName).toBe('string');
// Enrichment fields added by steal #10.
expect(body.configuredProvider).toBe('auto'); // fresh config → default
expect(typeof body.envOverride).toBe('boolean');
expect(body.envOverride).toBe(false); // beforeEach cleared the env var
});
it('POST /api/embedding/provider rejects an unknown provider with 400', async () => {
const res = await injectWithAuth(server, {
method: 'POST',
url: '/api/embedding/provider',
payload: { provider: 'banana' },
});
expect(res.statusCode).toBe(400);
});
it('POST /api/embedding/provider rejects "mock" with 400 (not user-selectable)', async () => {
const res = await injectWithAuth(server, {
method: 'POST',
url: '/api/embedding/provider',
payload: { provider: 'mock' },
});
expect(res.statusCode).toBe(400);
});
it('POST /api/embedding/provider tier-gates litellm on FREE with 403', async () => {
const res = await injectWithAuth(server, {
method: 'POST',
url: '/api/embedding/provider',
payload: { provider: 'litellm' },
});
expect(res.statusCode).toBe(403);
const body = JSON.parse(res.body);
expect(body.error).toBe('TIER_REQUIRED');
expect(body.requiredTier).toBeDefined();
expect(body.currentTier).toBe('FREE');
// Rejected write must not have persisted.
expect(readConfig().embedding).toBeUndefined();
});
it('POST /api/embedding/provider persists "auto" (no restart required)', async () => {
const res = await injectWithAuth(server, {
method: 'POST',
url: '/api/embedding/provider',
payload: { provider: 'auto' },
});
expect(res.statusCode).toBe(200);
const body = JSON.parse(res.body);
expect(body.configuredProvider).toBe('auto');
expect(body.restartRequired).toBe(false);
expect((readConfig().embedding as { provider?: string }).provider).toBe('auto');
});
it('POST /api/embedding/provider persists a tier-allowed provider with restartRequired', async () => {
const res = await injectWithAuth(server, {
method: 'POST',
url: '/api/embedding/provider',
payload: { provider: 'inprocess' }, // FREE allows inprocess
});
expect(res.statusCode).toBe(200);
const body = JSON.parse(res.body);
expect(body.configuredProvider).toBe('inprocess');
// Active provider at boot is mock (test env), so switching needs a restart.
expect(body.restartRequired).toBe(true);
expect((readConfig().embedding as { provider?: string }).provider).toBe('inprocess');
});
it('POST /api/embedding/provider rejects the write when EMBEDDING_PROVIDER env is set', async () => {
process.env.EMBEDDING_PROVIDER = 'voyage';
// config currently persists 'inprocess' from the previous test.
const res = await injectWithAuth(server, {
method: 'POST',
url: '/api/embedding/provider',
payload: { provider: 'auto' },
});
expect(res.statusCode).toBe(409);
const body = JSON.parse(res.body);
expect(body.error).toBe('EMBEDDING_PROVIDER_ENV_OVERRIDE');
expect(body.envOverride).toBe(true);
// The env-forced write must not have changed the persisted choice.
expect((readConfig().embedding as { provider?: string }).provider).toBe('inprocess');
// And status reports the override too.
const statusRes = await injectWithAuth(server, { method: 'GET', url: '/api/embedding/status' });
expect(JSON.parse(statusRes.body).envOverride).toBe(true);
});
});