This commit is contained in:
Oleg Maslov
2026-09-02 10:14:22 +02:00
parent 0c3e2ead3b
commit b20b138fe4
771 changed files with 161561 additions and 9027 deletions

View File

@@ -1,6 +1,7 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import Fastify from 'fastify';
import { localInferenceRoutes } from '../../src/local/routes/local-inference.js';
import { ManagedRuntimeRollbackError } from '../../src/local/managed-ollama-runtime.js';
describe('local-inference route — TS engine wiring', () => {
let server: ReturnType<typeof Fastify>;
@@ -34,3 +35,793 @@ describe('local-inference route — TS engine wiring', () => {
expect(m.runtime).toBe('Ollama');
});
});
const unavailableOllama = {
type: 'ollama' as const,
available: false,
url: 'http://127.0.0.1:11434',
models: [],
cloudModels: [],
};
const unavailableVllm = {
type: 'vllm' as const,
available: false,
url: 'http://localhost:8000',
models: [],
cloudModels: [],
};
function managedStatus(supported = true) {
return {
source: 'waggle-managed' as const,
supported,
installed: false,
running: false,
targetVersion: 'test-1.0.0',
version: 'test-1.0.0',
targetInstalled: false,
activeVersion: null,
previousVersion: null,
fallbackActive: false,
rollback: {
available: false,
active: false,
lastAttempt: null,
},
artifactSizeBytes: 123,
downloadRequired: true,
dockerRequired: false as const,
...(!supported ? { reason: 'unsupported fixture' } : {}),
};
}
const rollbackAttempt = {
failedVersion: 'test-2.0.0',
restoredVersion: 'test-1.0.0',
occurredAt: '2026-07-21T09:00:00.000Z',
reason: 'target failed its readiness probe',
};
function managedRollbackStatus(running = true) {
return {
...managedStatus(),
installed: true,
running,
targetVersion: rollbackAttempt.failedVersion,
version: rollbackAttempt.restoredVersion,
targetInstalled: true,
activeVersion: rollbackAttempt.restoredVersion,
previousVersion: null,
fallbackActive: true,
rollback: {
available: true,
active: true,
lastAttempt: rollbackAttempt,
},
downloadRequired: false,
};
}
describe('local-inference route — Waggle-managed runtime', () => {
it('forwards target, active, previous, and rollback state without flattening it', async () => {
const server = Fastify({ logger: false });
const rollbackStatus = managedRollbackStatus();
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => rollbackStatus,
ensureReady: vi.fn(),
startInstalled: vi.fn(),
stop: async () => undefined,
}),
ollamaProbe: async () => unavailableOllama,
vllmProbe: async () => unavailableVllm,
});
const response = await server.inject({ method: 'GET', url: '/api/local-inference/status' });
expect(response.statusCode).toBe(200);
expect(response.json().managedRuntime).toEqual(rollbackStatus);
await server.close();
});
it('advertises a Docker-free managed bootstrap instead of requiring a system Ollama install', async () => {
const server = Fastify({ logger: false });
const stop = vi.fn(async () => undefined);
const ensureReady = vi.fn();
const startInstalled = vi.fn();
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => managedStatus(),
ensureReady,
startInstalled,
stop,
}),
ollamaProbe: async () => unavailableOllama,
vllmProbe: async () => unavailableVllm,
});
const response = await server.inject({ method: 'GET', url: '/api/local-inference/status' });
expect(response.statusCode).toBe(200);
expect(response.json()).toMatchObject({
ollamaInstalled: false,
ollamaRunning: false,
offlineReady: false,
dockerRequired: false,
managedRuntime: { supported: true, downloadRequired: true, dockerRequired: false },
});
expect(response.json().setupMessage).toMatch(/system Ollama install (?:is|are) not required/i);
expect(ensureReady).not.toHaveBeenCalled();
expect(startInstalled).not.toHaveBeenCalled();
await server.close();
expect(stop).toHaveBeenCalledOnce();
});
it('restarts an active fallback runtime on sidecar start without retrying the upgrade', async () => {
const server = Fastify({ logger: false });
const installedStatus = managedRollbackStatus(false);
const runningStatus = { ...installedStatus, running: true };
const ensureReady = vi.fn();
const startInstalled = vi.fn(async () => ({
installedNow: false,
startedNow: true,
endpoint: 'http://127.0.0.1:11434',
status: runningStatus,
}));
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => installedStatus,
ensureReady,
startInstalled,
stop: async () => undefined,
}),
ollamaProbe: async () => unavailableOllama,
vllmProbe: async () => unavailableVllm,
});
await server.ready();
expect(startInstalled).toHaveBeenCalledOnce();
await expect(startInstalled.mock.results[0]?.value).resolves.toMatchObject({
installedNow: false,
startedNow: true,
});
expect(ensureReady).not.toHaveBeenCalled();
await server.close();
});
it('does not auto-start an older active runtime before an explicit target upgrade', async () => {
const server = Fastify({ logger: false });
const pendingUpgradeStatus = {
...managedStatus(),
installed: true,
running: false,
targetVersion: 'test-2.0.0',
version: 'test-1.0.0',
targetInstalled: true,
activeVersion: 'test-1.0.0',
previousVersion: null,
fallbackActive: false,
rollback: {
available: true,
active: false,
lastAttempt: null,
},
downloadRequired: false,
};
const ensureReady = vi.fn();
const startInstalled = vi.fn();
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => pendingUpgradeStatus,
ensureReady,
startInstalled,
stop: async () => undefined,
}),
ollamaProbe: async () => unavailableOllama,
vllmProbe: async () => unavailableVllm,
});
await server.ready();
expect(startInstalled).not.toHaveBeenCalled();
expect(ensureReady).not.toHaveBeenCalled();
await server.close();
});
it('keeps the sidecar available when an installed runtime cannot restart', async () => {
const server = Fastify({ logger: false });
const installedStatus = {
...managedStatus(),
installed: true,
running: false,
targetInstalled: true,
downloadRequired: false,
};
const ensureReady = vi.fn();
const startInstalled = vi.fn(async () => {
throw new Error('runtime blocked by quarantine');
});
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => installedStatus,
ensureReady,
startInstalled,
stop: async () => undefined,
}),
ollamaProbe: async () => unavailableOllama,
vllmProbe: async () => unavailableVllm,
});
const response = await server.inject({ method: 'GET', url: '/api/local-inference/status' });
expect(response.statusCode).toBe(200);
expect(response.json()).toMatchObject({
ollamaInstalled: true,
ollamaRunning: false,
offlineReady: false,
});
expect(startInstalled).toHaveBeenCalledOnce();
expect(ensureReady).not.toHaveBeenCalled();
await server.close();
});
it('does not delay sidecar readiness and stops again after a close during restart', async () => {
const server = Fastify({ logger: false });
const installedStatus = {
...managedStatus(),
installed: true,
running: false,
targetInstalled: true,
downloadRequired: false,
};
let finishRestart!: () => void;
const restartReleased = new Promise<void>((resolve) => { finishRestart = resolve; });
const startInstalled = vi.fn(async () => {
await restartReleased;
return {
installedNow: false,
startedNow: true,
endpoint: 'http://127.0.0.1:11434',
status: { ...installedStatus, running: true },
};
});
const stop = vi.fn(async () => undefined);
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => installedStatus,
ensureReady: vi.fn(),
startInstalled,
stop,
}),
ollamaProbe: async () => unavailableOllama,
vllmProbe: async () => unavailableVllm,
});
const readyOutcome = await Promise.race([
server.ready().then(() => 'ready' as const),
new Promise<'blocked'>((resolve) => setTimeout(() => resolve('blocked'), 500)),
]);
expect(readyOutcome).toBe('ready');
expect(startInstalled).toHaveBeenCalledOnce();
await server.close();
expect(stop).toHaveBeenCalledOnce();
finishRestart();
await vi.waitFor(() => expect(stop).toHaveBeenCalledTimes(2));
});
it('installs, starts, and health-checks the managed runtime through one bootstrap route', async () => {
const server = Fastify({ logger: false });
const readyStatus = {
...managedStatus(),
installed: true,
running: true,
targetInstalled: true,
activeVersion: 'test-1.0.0',
downloadRequired: false,
};
const ensureReady = vi.fn(async () => ({
installedNow: true,
startedNow: true,
endpoint: 'http://127.0.0.1:11434',
status: readyStatus,
}));
const ollamaProbe = vi.fn()
.mockResolvedValueOnce(unavailableOllama)
.mockResolvedValueOnce({
...unavailableOllama,
available: true,
models: [],
version: 'test-1.0.0',
});
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => managedStatus(),
ensureReady,
startInstalled: vi.fn(),
stop: async () => undefined,
}),
ollamaProbe,
vllmProbe: async () => unavailableVllm,
});
const response = await server.inject({ method: 'POST', url: '/api/local-inference/bootstrap' });
expect(response.statusCode).toBe(200);
expect(response.json()).toMatchObject({
ok: true,
installedNow: true,
startedNow: true,
dockerRequired: false,
server: { available: true, version: 'test-1.0.0' },
status: {
activeVersion: 'test-1.0.0',
fallbackActive: false,
rollback: {
available: false,
active: false,
lastAttempt: null,
},
},
});
expect(ensureReady).toHaveBeenCalledOnce();
expect(ollamaProbe).toHaveBeenCalledTimes(2);
await server.close();
});
it('reports a failed target upgrade after the verified prior runtime is restored', async () => {
const server = Fastify({ logger: false });
const rollbackStatus = managedRollbackStatus();
const ensureReady = vi.fn(async () => {
throw new ManagedRuntimeRollbackError(rollbackAttempt, new Error(rollbackAttempt.reason));
});
const ollamaProbe = vi.fn()
.mockResolvedValueOnce(unavailableOllama)
.mockResolvedValueOnce({
...unavailableOllama,
available: true,
version: 'test-1.0.0',
});
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => rollbackStatus,
ensureReady,
startInstalled: vi.fn(),
stop: async () => undefined,
}),
ollamaProbe,
vllmProbe: async () => unavailableVllm,
});
const response = await server.inject({ method: 'POST', url: '/api/local-inference/bootstrap' });
expect(response.statusCode).toBe(502);
const body = response.json();
expect(body).toMatchObject({
ok: false,
code: 'MANAGED_RUNTIME_ROLLED_BACK',
server: { available: true, version: 'test-1.0.0' },
});
expect(body.managedRuntime).toEqual(rollbackStatus);
expect(body).not.toHaveProperty('installedNow');
expect(body).not.toHaveProperty('startedNow');
expect(ensureReady).toHaveBeenCalledOnce();
expect(ollamaProbe).toHaveBeenCalledTimes(2);
await server.close();
});
it('does not claim bootstrap success when the already-running endpoint is a restored fallback', async () => {
const server = Fastify({ logger: false });
const rollbackStatus = managedRollbackStatus();
const ensureReady = vi.fn(async () => ({
installedNow: false,
startedNow: false,
endpoint: 'http://127.0.0.1:11434',
status: rollbackStatus,
}));
const restoredServer = {
...unavailableOllama,
available: true,
version: 'test-1.0.0',
};
const ollamaProbe = vi.fn(async () => restoredServer);
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => rollbackStatus,
ensureReady,
startInstalled: vi.fn(),
stop: async () => undefined,
}),
ollamaProbe,
vllmProbe: async () => unavailableVllm,
});
const response = await server.inject({ method: 'POST', url: '/api/local-inference/bootstrap' });
expect(response.statusCode).toBe(502);
expect(response.json()).toEqual(expect.objectContaining({
ok: false,
code: 'MANAGED_RUNTIME_ROLLED_BACK',
server: restoredServer,
managedRuntime: rollbackStatus,
}));
expect(ensureReady).toHaveBeenCalledOnce();
expect(ollamaProbe).toHaveBeenCalledTimes(2);
await server.close();
});
it('waits for managed activation to commit when the runtime already answers loopback', async () => {
const server = Fastify({ logger: false });
const activatingStatus = {
...managedStatus(),
installed: true,
running: true,
targetInstalled: true,
downloadRequired: false,
};
const readyStatus = {
...activatingStatus,
activeVersion: 'test-1.0.0',
};
const ensureReady = vi.fn(async () => ({
installedNow: false,
startedNow: false,
endpoint: 'http://127.0.0.1:11434',
status: readyStatus,
}));
const existingServer = {
...unavailableOllama,
available: true,
version: 'test-1.0.0',
};
const ollamaProbe = vi.fn(async () => existingServer);
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => activatingStatus,
ensureReady,
startInstalled: vi.fn(),
stop: async () => undefined,
}),
ollamaProbe,
vllmProbe: async () => unavailableVllm,
});
const response = await server.inject({ method: 'POST', url: '/api/local-inference/bootstrap' });
expect(response.statusCode).toBe(200);
expect(response.json()).toMatchObject({
ok: true,
installedNow: false,
startedNow: false,
server: existingServer,
status: { activeVersion: 'test-1.0.0', fallbackActive: false },
});
expect(ensureReady).toHaveBeenCalledOnce();
expect(ollamaProbe).toHaveBeenCalledTimes(2);
await server.close();
});
it('preserves bootstrap success for an already-running endpoint that is not a fallback', async () => {
const server = Fastify({ logger: false });
const status = managedStatus();
const ensureReady = vi.fn(async () => ({
installedNow: false,
startedNow: false,
endpoint: 'http://127.0.0.1:11434',
status,
}));
const existingServer = {
...unavailableOllama,
available: true,
version: 'system-1.0.0',
};
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => status,
ensureReady,
startInstalled: vi.fn(),
stop: async () => undefined,
}),
ollamaProbe: async () => existingServer,
vllmProbe: async () => unavailableVllm,
});
const response = await server.inject({ method: 'POST', url: '/api/local-inference/bootstrap' });
expect(response.statusCode).toBe(200);
expect(response.json()).toMatchObject({
ok: true,
installedNow: false,
startedNow: false,
server: existingServer,
status,
});
expect(ensureReady).toHaveBeenCalledOnce();
await server.close();
});
it('does not turn a fallback result into bootstrap success after a probe race', async () => {
const server = Fastify({ logger: false });
const rollbackStatus = managedRollbackStatus();
const ensureReady = vi.fn(async () => ({
installedNow: false,
startedNow: false,
endpoint: 'http://127.0.0.1:11434',
status: rollbackStatus,
}));
const restoredServer = {
...unavailableOllama,
available: true,
version: 'test-1.0.0',
};
const ollamaProbe = vi.fn()
.mockResolvedValueOnce(unavailableOllama)
.mockResolvedValueOnce(restoredServer);
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => rollbackStatus,
ensureReady,
startInstalled: vi.fn(),
stop: async () => undefined,
}),
ollamaProbe,
vllmProbe: async () => unavailableVllm,
});
const response = await server.inject({ method: 'POST', url: '/api/local-inference/bootstrap' });
expect(response.statusCode).toBe(502);
expect(response.json()).toEqual(expect.objectContaining({
ok: false,
code: 'MANAGED_RUNTIME_ROLLED_BACK',
server: restoredServer,
managedRuntime: rollbackStatus,
}));
expect(response.json()).not.toHaveProperty('installedNow');
expect(response.json()).not.toHaveProperty('startedNow');
expect(ensureReady).toHaveBeenCalledOnce();
expect(ollamaProbe).toHaveBeenCalledTimes(2);
await server.close();
});
it('keeps the generic bootstrap failure contract for failures without a restored runtime', async () => {
const server = Fastify({ logger: false });
const ensureReady = vi.fn(async () => {
throw new Error('runtime download blocked');
});
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => managedStatus(),
ensureReady,
startInstalled: vi.fn(),
stop: async () => undefined,
}),
ollamaProbe: async () => unavailableOllama,
vllmProbe: async () => unavailableVllm,
});
const response = await server.inject({ method: 'POST', url: '/api/local-inference/bootstrap' });
expect(response.statusCode).toBe(502);
expect(response.json()).toEqual({
error: 'runtime download blocked',
code: 'MANAGED_RUNTIME_BOOTSTRAP_FAILED',
managedRuntime: managedStatus(),
});
expect(ensureReady).toHaveBeenCalledOnce();
await server.close();
});
it('returns a truthful unsupported-platform contract without attempting a download', async () => {
const server = Fastify({ logger: false });
const ensureReady = vi.fn();
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => managedStatus(false),
ensureReady,
startInstalled: vi.fn(),
stop: async () => undefined,
}),
ollamaProbe: async () => unavailableOllama,
vllmProbe: async () => unavailableVllm,
});
const response = await server.inject({ method: 'POST', url: '/api/local-inference/bootstrap' });
expect(response.statusCode).toBe(409);
expect(response.json()).toMatchObject({
code: 'MANAGED_RUNTIME_UNSUPPORTED',
managedRuntime: { supported: false },
});
expect(ensureReady).not.toHaveBeenCalled();
await server.close();
});
});
describe('local-inference route — verified model installation', () => {
async function buildPullServer(
models: string[],
modelDigests: Record<string, string> = Object.fromEntries(
models.map((model) => [model, `sha256:${'a'.repeat(64)}`]),
),
) {
const server = Fastify({ logger: false });
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => ({ ...managedStatus(), installed: true, running: true, downloadRequired: false }),
ensureReady: vi.fn(),
startInstalled: vi.fn(),
stop: async () => undefined,
}),
ollamaProbe: async () => ({
type: 'ollama',
available: true,
url: 'http://127.0.0.1:11434',
models,
modelDigests,
cloudModels: [],
version: 'test-1.0.0',
}),
vllmProbe: async () => unavailableVllm,
});
return server;
}
it('rejects cloud aliases and malformed refs before any download', async () => {
const fetchMock = vi.fn();
vi.stubGlobal('fetch', fetchMock);
const server = await buildPullServer([]);
try {
const missing = await server.inject({
method: 'POST',
url: '/api/local-inference/pull',
});
expect(missing.statusCode).toBe(400);
expect(missing.json().code).toBe('MODEL_REQUIRED');
const cloud = await server.inject({
method: 'POST',
url: '/api/local-inference/pull',
payload: { model: 'minimax-m2.7:cloud' },
});
expect(cloud.statusCode).toBe(400);
expect(cloud.json().code).toBe('REMOTE_MODEL_NOT_LOCAL');
const malformed = await server.inject({
method: 'POST',
url: '/api/local-inference/pull',
payload: { model: 'trusted/../../escape' },
});
expect(malformed.statusCode).toBe(400);
expect(malformed.json().code).toBe('INVALID_MODEL_REF');
expect(fetchMock).not.toHaveBeenCalled();
} finally {
await server.close();
vi.unstubAllGlobals();
}
});
it('reports ready only after the pulled local model produces a real token', async () => {
const fetchMock = vi.fn()
.mockResolvedValueOnce(new Response(JSON.stringify({ status: 'success' }), {
status: 200,
headers: { 'content-type': 'application/json' },
}))
.mockResolvedValueOnce(new Response(JSON.stringify({ response: 'OK', done: true }), {
status: 200,
headers: { 'content-type': 'application/json' },
}));
vi.stubGlobal('fetch', fetchMock);
const server = await buildPullServer(['qwen3:1.7b']);
try {
const response = await server.inject({
method: 'POST',
url: '/api/local-inference/pull',
payload: { model: 'qwen3:1.7b' },
});
expect(response.statusCode).toBe(200);
expect(response.json()).toMatchObject({
ok: true,
model: 'qwen3:1.7b',
digest: `sha256:${'a'.repeat(64)}`,
verifiedGeneration: true,
sample: 'OK',
});
expect(fetchMock).toHaveBeenNthCalledWith(2,
'http://127.0.0.1:11434/api/generate',
expect.objectContaining({ method: 'POST' }),
);
expect(JSON.parse(String(fetchMock.mock.calls[1]?.[1]?.body))).toMatchObject({
model: 'qwen3:1.7b',
stream: false,
think: false,
options: { temperature: 0, num_predict: 8 },
});
} finally {
await server.close();
vi.unstubAllGlobals();
}
});
it('canonicalizes the bare digest advertised by the live Ollama tag API', async () => {
const wireDigest = 'B'.repeat(64);
const digest = `sha256:${'b'.repeat(64)}`;
const fetchMock = vi.fn(async (input: string | URL | Request) => {
const url = String(input);
if (url.endsWith('/api/pull')) {
return new Response(JSON.stringify({ status: 'success' }), { status: 200 });
}
if (url.endsWith('/api/tags')) {
return new Response(JSON.stringify({
models: [{ name: 'qwen3:1.7b', digest: wireDigest }],
}), { status: 200, headers: { 'content-type': 'application/json' } });
}
if (url.endsWith('/api/version')) {
return new Response(JSON.stringify({ version: 'test-1.0.0' }), { status: 200 });
}
if (url.endsWith('/api/generate')) {
return new Response(JSON.stringify({ response: 'OK', done: true }), { status: 200 });
}
return new Response('', { status: 503 });
});
vi.stubGlobal('fetch', fetchMock);
const server = Fastify({ logger: false });
await server.register(localInferenceRoutes, {
runtimeFactory: () => ({
getStatus: () => ({ ...managedStatus(), installed: true, running: true }),
ensureReady: vi.fn(),
startInstalled: vi.fn(),
stop: async () => undefined,
}),
vllmProbe: async () => unavailableVllm,
});
try {
const response = await server.inject({
method: 'POST',
url: '/api/local-inference/pull',
payload: { model: 'qwen3:1.7b' },
});
expect(response.statusCode).toBe(200);
expect(response.json()).toMatchObject({ model: 'qwen3:1.7b', digest });
} finally {
await server.close();
vi.unstubAllGlobals();
}
});
it('fails closed when Ollama does not advertise an immutable model digest', async () => {
const fetchMock = vi.fn()
.mockResolvedValueOnce(new Response(JSON.stringify({ status: 'success' }), { status: 200 }));
vi.stubGlobal('fetch', fetchMock);
const server = await buildPullServer(['qwen3:1.7b'], {});
try {
const response = await server.inject({
method: 'POST',
url: '/api/local-inference/pull',
payload: { model: 'qwen3:1.7b' },
});
expect(response.statusCode).toBe(502);
expect(response.json()).toMatchObject({
code: 'MODEL_DIGEST_UNAVAILABLE',
model: 'qwen3:1.7b',
});
expect(fetchMock).toHaveBeenCalledTimes(1);
} finally {
await server.close();
vi.unstubAllGlobals();
}
});
it('does not claim readiness when an installed model fails generation', async () => {
const fetchMock = vi.fn()
.mockResolvedValueOnce(new Response(JSON.stringify({ status: 'success' }), { status: 200 }))
.mockResolvedValueOnce(new Response('model failed to load', { status: 500 }));
vi.stubGlobal('fetch', fetchMock);
const server = await buildPullServer(['qwen3:1.7b']);
try {
const response = await server.inject({
method: 'POST',
url: '/api/local-inference/pull',
payload: { model: 'qwen3:1.7b' },
});
expect(response.statusCode).toBe(502);
expect(response.json()).toMatchObject({
code: 'MODEL_GENERATION_PROBE_FAILED',
installed: true,
model: 'qwen3:1.7b',
});
} finally {
await server.close();
vi.unstubAllGlobals();
}
});
});