/** * 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); } // ── Resolve default endpoint for selected provider ── var defaultEndpoint = ''; if (selectedProvider) { try { var typesResp = await T.raw.get('/admin/provider-types'); var types = typesResp.types || typesResp.data || typesResp || []; var match = types.find ? types.find(function (t) { return t.id === selectedProvider; }) : null; if (match) defaultEndpoint = match.default_endpoint || ''; } catch (_) { /* best effort — endpoint will be required in payload */ } } // 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, endpoint: defaultEndpoint, 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, endpoint: defaultEndpoint, 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'); }; })();