Co-authored-by: gobha <jasafpro@gmail.com> Co-committed-by: gobha <jasafpro@gmail.com>
240 lines
8.2 KiB
JavaScript
240 lines
8.2 KiB
JavaScript
/**
|
|
* SDK Test Runner — Fixtures
|
|
*
|
|
* Provisions reusable test resources before domains run and tears
|
|
* them down afterward. Modeled on the ICD test runner's fixture
|
|
* pattern.
|
|
*
|
|
* Fixture resources (all optional — domains degrade gracefully):
|
|
*
|
|
* providerConfig Global API config created from the first admin
|
|
* config that has at least one embedding model.
|
|
* Enables: knowledge.search, model preference tests.
|
|
*
|
|
* embeddingModel {model_id, provider_config_id} picked from the
|
|
* enabled models list after the config is created.
|
|
*
|
|
* policies Policy toggles applied at setup, reverted at
|
|
* teardown (e.g. allow_user_personas).
|
|
*
|
|
* team Test team (with current user as admin).
|
|
*
|
|
* Access: window.SDKR.fixtures.*
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
var T = window.SDKR;
|
|
if (!T) return;
|
|
|
|
T.fixtures = {
|
|
ready: false,
|
|
providerConfig: null, // { id, name, provider }
|
|
embeddingModel: null, // { model_id, provider_config_id }
|
|
team: null, // { id, name }
|
|
policies: {}, // key → original value (for revert)
|
|
errors: []
|
|
};
|
|
|
|
// ─── Policy helpers ──────────────────────────────────────
|
|
|
|
async function setPolicy(key, value) {
|
|
var fix = T.fixtures;
|
|
try {
|
|
// Save original for revert
|
|
if (!(key in fix.policies)) {
|
|
try {
|
|
var settings = await T.raw.get('/admin/settings');
|
|
fix.policies[key] = settings.policies?.[key] ?? null;
|
|
} catch (_) {
|
|
fix.policies[key] = null;
|
|
}
|
|
}
|
|
await T.raw.put('/admin/settings/' + key, { value: String(value) });
|
|
} catch (e) {
|
|
fix.errors.push('policy ' + key + ': ' + e.message);
|
|
}
|
|
}
|
|
|
|
async function revertPolicies() {
|
|
var fix = T.fixtures;
|
|
var keys = Object.keys(fix.policies);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var val = fix.policies[keys[i]];
|
|
try {
|
|
await T.raw.put('/admin/settings/' + keys[i], {
|
|
value: val === null ? 'false' : String(val)
|
|
});
|
|
} catch (_) { /* best effort */ }
|
|
}
|
|
}
|
|
|
|
// ─── Provider / model discovery ──────────────────────────
|
|
|
|
async function provisionProvider() {
|
|
var fix = T.fixtures;
|
|
|
|
// ── Read UI inputs (provider + API key) ──
|
|
var ui = T._fixtureInput || {};
|
|
var selectedProvider = ui.provSelect ? ui.provSelect.value : '';
|
|
var apiKey = ui.keyInput ? ui.keyInput.value.trim() : '';
|
|
var statusEl = ui.statusEl;
|
|
|
|
function setStatus(msg) {
|
|
if (statusEl) statusEl.textContent = msg;
|
|
console.log('[SDKR:fixtures] ' + msg);
|
|
}
|
|
|
|
// Check if any configs already exist
|
|
try {
|
|
var configs = await T.raw.get('/admin/configs');
|
|
var list = configs.data || configs.configs || [];
|
|
if (list.length > 0) {
|
|
fix.providerConfig = { id: list[0].id, name: list[0].name, provider: list[0].provider };
|
|
setStatus('Using existing config: ' + list[0].name);
|
|
}
|
|
} catch (e) {
|
|
fix.errors.push('config list: ' + e.message);
|
|
return;
|
|
}
|
|
|
|
// If no config exists and user provided a provider + key, create one
|
|
if (!fix.providerConfig && selectedProvider && apiKey) {
|
|
try {
|
|
var configData = {
|
|
name: 'sdkr-fixture-' + selectedProvider,
|
|
provider: selectedProvider,
|
|
api_key: apiKey,
|
|
scope: 'global'
|
|
};
|
|
setStatus('Creating ' + selectedProvider + ' config...');
|
|
var created = await T.raw.post('/admin/configs', configData);
|
|
if (created && created.id) {
|
|
fix.providerConfig = { id: created.id, name: configData.name, provider: selectedProvider };
|
|
fix._createdConfig = true; // mark for cleanup
|
|
setStatus('Config created: ' + configData.name);
|
|
T.registerCleanup(function () {
|
|
if (fix._createdConfig && fix.providerConfig) {
|
|
return T.safeDelete('/admin/configs/' + fix.providerConfig.id);
|
|
}
|
|
});
|
|
}
|
|
} catch (e) {
|
|
setStatus('Config create failed: ' + e.message);
|
|
fix.errors.push('config create: ' + e.message);
|
|
}
|
|
} else if (!fix.providerConfig && selectedProvider && !apiKey) {
|
|
// Provider selected but no key — try creating without key (some providers
|
|
// use server-side keys configured via env vars)
|
|
try {
|
|
var configData2 = {
|
|
name: 'sdkr-fixture-' + selectedProvider,
|
|
provider: selectedProvider,
|
|
scope: 'global'
|
|
};
|
|
var created2 = await T.raw.post('/admin/configs', configData2);
|
|
if (created2 && created2.id) {
|
|
fix.providerConfig = { id: created2.id, name: configData2.name, provider: selectedProvider };
|
|
fix._createdConfig = true;
|
|
setStatus('Config created (server key): ' + configData2.name);
|
|
T.registerCleanup(function () {
|
|
if (fix._createdConfig && fix.providerConfig) {
|
|
return T.safeDelete('/admin/configs/' + fix.providerConfig.id);
|
|
}
|
|
});
|
|
}
|
|
} catch (_) {
|
|
setStatus('No config — skipping model tests');
|
|
}
|
|
} else if (!fix.providerConfig) {
|
|
setStatus('No provider selected — model tests will be skipped');
|
|
}
|
|
|
|
// Fetch models if we have a config
|
|
if (fix.providerConfig) {
|
|
try {
|
|
await T.raw.post('/admin/models/fetch', {});
|
|
// Wait briefly for async model fetch
|
|
await new Promise(function (r) { setTimeout(r, 1500); });
|
|
} catch (_) { /* fetch may fail if no key */ }
|
|
|
|
// Look for an embedding model
|
|
try {
|
|
var models = await T.raw.get('/models/enabled');
|
|
var list2 = models.data || [];
|
|
for (var m = 0; m < list2.length; m++) {
|
|
var caps = list2[m].capabilities || {};
|
|
if (caps.embedding || list2[m].model_type === 'embedding') {
|
|
fix.embeddingModel = {
|
|
model_id: list2[m].model_id,
|
|
provider_config_id: list2[m].provider_config_id
|
|
};
|
|
console.log('[SDKR:fixtures] Embedding model: ' + list2[m].model_id);
|
|
break;
|
|
}
|
|
}
|
|
} catch (_) { /* no models available */ }
|
|
}
|
|
}
|
|
|
|
// ─── Team ────────────────────────────────────────────────
|
|
|
|
async function provisionTeam() {
|
|
var fix = T.fixtures;
|
|
try {
|
|
var team = await T.raw.post('/admin/teams', {
|
|
name: 'sdkr-fixture-' + Date.now(),
|
|
description: 'SDK test runner fixture team'
|
|
});
|
|
if (team && team.id) {
|
|
fix.team = { id: team.id, name: team.name };
|
|
T.registerCleanup(function () {
|
|
if (fix.team) return T.safeDelete('/admin/teams/' + fix.team.id);
|
|
});
|
|
}
|
|
} catch (e) {
|
|
fix.errors.push('team: ' + e.message);
|
|
}
|
|
}
|
|
|
|
// ─── Provision / Teardown ────────────────────────────────
|
|
|
|
T.provisionFixtures = async function () {
|
|
var fix = T.fixtures;
|
|
if (fix.ready) return;
|
|
|
|
console.log('[SDKR:fixtures] Provisioning...');
|
|
|
|
// Policies
|
|
await setPolicy('allow_user_personas', 'true');
|
|
|
|
// Provider + models
|
|
await provisionProvider();
|
|
|
|
// Team
|
|
await provisionTeam();
|
|
|
|
fix.ready = true;
|
|
|
|
if (fix.errors.length > 0) {
|
|
console.warn('[SDKR:fixtures] ' + fix.errors.length + ' errors:', fix.errors);
|
|
}
|
|
console.log('[SDKR:fixtures] Ready —',
|
|
'config:', fix.providerConfig ? fix.providerConfig.name : 'none',
|
|
'| embedding:', fix.embeddingModel ? fix.embeddingModel.model_id : 'none',
|
|
'| team:', fix.team ? fix.team.name : 'none'
|
|
);
|
|
};
|
|
|
|
T.teardownFixtures = async function () {
|
|
await revertPolicies();
|
|
// Cleanup functions registered via T.registerCleanup handle
|
|
// the config + team deletion.
|
|
T.fixtures = {
|
|
ready: false, providerConfig: null, embeddingModel: null,
|
|
team: null, policies: {}, errors: []
|
|
};
|
|
console.log('[SDKR:fixtures] Torn down');
|
|
};
|
|
|
|
})();
|