Feat v0.7.1 surface runner framework (#55)
All checks were successful
All checks were successful
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #55.
This commit is contained in:
@@ -1,20 +1,21 @@
|
||||
/**
|
||||
* SDK Test Runner — Domain: admin
|
||||
*
|
||||
* Tests admin-scoped endpoints. Requires admin role.
|
||||
* KNOWN ISSUES: some admin list endpoints use non-standard envelope
|
||||
* keys (§E in ICD drift audit).
|
||||
* Tests kernel admin endpoints. Requires admin role.
|
||||
* Extension admin endpoints (configs, models, tasks, routing,
|
||||
* providers/health, channels/archived, projects, cluster) belong
|
||||
* in package runners, not here.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var T = window.SDKR;
|
||||
if (!T) return;
|
||||
|
||||
T.registerDomain('admin', async function () {
|
||||
sw.testing.suite('sdk/admin', async function (s) {
|
||||
|
||||
// Guard: skip if not admin
|
||||
if (!window.sw || !sw.isAdmin) {
|
||||
await T.test('admin', 'guard', 'skip — not admin', async function () {
|
||||
s.test('guard: skip — not admin', async function (t) {
|
||||
T.assert(true, 'skipped (user is not admin)');
|
||||
});
|
||||
return;
|
||||
@@ -22,166 +23,226 @@
|
||||
|
||||
// ── Users ──
|
||||
|
||||
await T.test('admin', 'users', 'sw.api.admin.users.list()', {
|
||||
sdk: function () { return sw.api.admin.users.list(); },
|
||||
raw: { method: 'GET', path: '/admin/users' },
|
||||
validate: function (r) {
|
||||
// KNOWN: backend returns {users: [...]} not {data: [...]}
|
||||
var arr = r;
|
||||
if (r && r.users) arr = r.users;
|
||||
if (r && r.data) arr = r.data;
|
||||
T.assert(Array.isArray(arr), 'expected array (maybe wrapped in non-standard key)');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Configs (provider configs) ──
|
||||
|
||||
await T.test('admin', 'configs', 'sw.api.admin.configs.list()', {
|
||||
sdk: function () { return sw.api.admin.configs.list(); },
|
||||
raw: { method: 'GET', path: '/admin/configs' },
|
||||
validate: function (r) {
|
||||
// KNOWN: backend returns {configs: [...]} not {data: [...]}
|
||||
var arr = r;
|
||||
if (r && r.configs) arr = r.configs;
|
||||
if (r && r.data) arr = r.data;
|
||||
T.assert(Array.isArray(arr), 'expected array');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Models ──
|
||||
|
||||
await T.test('admin', 'models', 'sw.api.admin.models.list()', {
|
||||
sdk: function () { return sw.api.admin.models.list(); },
|
||||
raw: { method: 'GET', path: '/admin/models' },
|
||||
validate: function (r) {
|
||||
// KNOWN: backend returns {models: [...]} not {data: [...]}
|
||||
var arr = r;
|
||||
if (r && r.models) arr = r.models;
|
||||
if (r && r.data) arr = r.data;
|
||||
T.assert(Array.isArray(arr), 'expected array');
|
||||
}
|
||||
s.test('users: sw.api.admin.users.list()', async function (t) {
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.admin.users.list(); },
|
||||
{ method: 'GET', path: '/admin/users' },
|
||||
function (r) {
|
||||
// KNOWN: backend returns {users: [...]} not {data: [...]}
|
||||
var arr = r;
|
||||
if (r && r.users) arr = r.users;
|
||||
if (r && r.data) arr = r.data;
|
||||
T.assert(Array.isArray(arr), 'expected array (maybe wrapped in non-standard key)');
|
||||
}
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
|
||||
// ── Settings ──
|
||||
|
||||
await T.test('admin', 'settings', 'sw.api.admin.settings.get()', {
|
||||
sdk: function () { return sw.api.admin.settings.get(); },
|
||||
raw: { method: 'GET', path: '/admin/settings' },
|
||||
validate: function (r) { T.assert(typeof r === 'object', 'expected object'); }
|
||||
s.test('settings: sw.api.admin.settings.get()', async function (t) {
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.admin.settings.get(); },
|
||||
{ method: 'GET', path: '/admin/settings' },
|
||||
function (r) { T.assert(typeof r === 'object', 'expected object'); }
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
|
||||
// ── Teams ──
|
||||
|
||||
s.test('teams: GET /admin/teams (raw)', async function (t) {
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.get('/api/v1/admin/teams'); },
|
||||
{ method: 'GET', path: '/admin/teams' },
|
||||
function (r) { T.assert(r && Array.isArray(r.data), 'expected { data: [...] }'); }
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
|
||||
// ── Groups ──
|
||||
|
||||
s.test('groups: GET /admin/groups (raw)', async function (t) {
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.get('/api/v1/admin/groups'); },
|
||||
{ method: 'GET', path: '/admin/groups' },
|
||||
function (r) { T.assert(r && Array.isArray(r.data), 'expected { data: [...] }'); }
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
|
||||
// ── Packages ──
|
||||
|
||||
await T.test('admin', 'packages', 'sw.api.admin.packages.list()', {
|
||||
sdk: function () { return sw.api.admin.packages.list(); },
|
||||
raw: { method: 'GET', path: '/admin/packages' },
|
||||
validate: function (r) { T.assert(Array.isArray(r) || (r && Array.isArray(r.data)), 'expected array'); }
|
||||
s.test('packages: sw.api.admin.packages.list()', async function (t) {
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.admin.packages.list(); },
|
||||
{ method: 'GET', path: '/admin/packages' },
|
||||
function (r) { T.assert(Array.isArray(r) || (r && Array.isArray(r.data)), 'expected array'); }
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
|
||||
// ── Surfaces ──
|
||||
|
||||
await T.test('admin', 'surfaces', 'sw.api.admin.surfaces.list()', {
|
||||
sdk: function () { return sw.api.admin.surfaces.list(); },
|
||||
raw: { method: 'GET', path: '/admin/packages' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
s.test('surfaces: sw.api.admin.surfaces.list()', async function (t) {
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.admin.surfaces.list(); },
|
||||
{ method: 'GET', path: '/admin/packages' },
|
||||
function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
|
||||
// ── Extensions ──
|
||||
|
||||
await T.test('admin', 'extensions', 'sw.api.admin.extensions.list()', {
|
||||
sdk: function () { return sw.api.admin.extensions.list(); },
|
||||
raw: { method: 'GET', path: '/admin/extensions' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
s.test('extensions: sw.api.admin.extensions.list()', async function (t) {
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.admin.extensions.list(); },
|
||||
{ method: 'GET', path: '/admin/extensions' },
|
||||
function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
|
||||
// ── Tasks ──
|
||||
// ── Permissions ──
|
||||
|
||||
await T.test('admin', 'tasks', 'sw.api.admin.tasks.list()', {
|
||||
sdk: function () { return sw.api.admin.tasks.list(); },
|
||||
raw: { method: 'GET', path: '/admin/tasks' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
s.test('permissions: GET /admin/permissions (raw)', async function (t) {
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.get('/api/v1/admin/permissions'); },
|
||||
{ method: 'GET', path: '/admin/permissions' },
|
||||
function (r) { T.assert(r && r.permissions, 'expected permissions key'); }
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
|
||||
// ── Routing ──
|
||||
// ── Audit ──
|
||||
|
||||
await T.test('admin', 'routing', 'sw.api.admin.routing.policies()', {
|
||||
sdk: function () { return sw.api.admin.routing.policies(); },
|
||||
raw: { method: 'GET', path: '/admin/routing/policies' },
|
||||
validate: function (r) { T.assert(Array.isArray(r) || (r && Array.isArray(r.data)), 'expected array'); }
|
||||
s.test('audit: GET /admin/audit (raw)', async function (t) {
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.get('/api/v1/admin/audit'); },
|
||||
{ method: 'GET', path: '/admin/audit' },
|
||||
function (r) {
|
||||
T.assert(r && Array.isArray(r.data), 'expected { data: [...] }');
|
||||
T.assert(typeof r.total === 'number', 'expected total');
|
||||
}
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
|
||||
// ── Provider health ──
|
||||
|
||||
await T.test('admin', 'providers', 'sw.api.admin.providers.health()', {
|
||||
sdk: function () { return sw.api.admin.providers.health(); },
|
||||
raw: { method: 'GET', path: '/admin/providers/health' },
|
||||
validate: function (r) { T.assert(typeof r === 'object' || Array.isArray(r), 'expected object or array'); }
|
||||
});
|
||||
|
||||
// ── Storage ──
|
||||
|
||||
await T.test('admin', 'storage', 'sw.api.admin.storage.status()', {
|
||||
sdk: function () { return sw.api.admin.storage.status(); },
|
||||
raw: { method: 'GET', path: '/admin/storage/status' },
|
||||
validate: function (r) { T.assert(typeof r === 'object', 'expected object'); }
|
||||
});
|
||||
|
||||
// ── Vault ──
|
||||
|
||||
await T.test('admin', 'vault', 'sw.api.admin.vault.status()', {
|
||||
sdk: function () { return sw.api.admin.vault.status(); },
|
||||
raw: { method: 'GET', path: '/admin/vault/status' },
|
||||
validate: function (r) { T.assert(typeof r === 'object', 'expected object'); }
|
||||
});
|
||||
|
||||
// ── Channels (archived) ──
|
||||
|
||||
await T.test('admin', 'channels', 'sw.api.admin.channels.archived()', {
|
||||
sdk: function () { return sw.api.admin.channels.archived(); },
|
||||
raw: { method: 'GET', path: '/admin/channels/archived' },
|
||||
validate: function (r) { T.assert(Array.isArray(r) || (r && Array.isArray(r.data)), 'expected array'); }
|
||||
});
|
||||
|
||||
// ── Projects ──
|
||||
|
||||
await T.test('admin', 'projects', 'sw.api.admin.projects.list()', {
|
||||
sdk: function () { return sw.api.admin.projects.list(); },
|
||||
raw: { method: 'GET', path: '/admin/projects' },
|
||||
validate: function (r) { T.assert(Array.isArray(r) || (r && Array.isArray(r.data)), 'expected array'); }
|
||||
s.test('audit: GET /admin/audit/actions (raw)', async function (t) {
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.get('/api/v1/admin/audit/actions'); },
|
||||
{ method: 'GET', path: '/admin/audit/actions' },
|
||||
function (r) { T.assert(r && r.actions, 'expected actions key'); }
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
|
||||
// ── Metrics (v0.6.4+) ──
|
||||
|
||||
await T.test('admin', 'metrics', 'GET /admin/metrics (raw)', {
|
||||
sdk: function () { return sw.api.get('/admin/metrics'); },
|
||||
raw: { method: 'GET', path: '/admin/metrics' },
|
||||
validate: function (r) {
|
||||
T.assert(typeof r === 'object', 'expected object');
|
||||
T.assertHasKey(r, 'runtime', 'metrics');
|
||||
T.assertHasKey(r, 'database', 'metrics');
|
||||
}
|
||||
s.test('metrics: GET /admin/metrics (raw)', async function (t) {
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.get('/api/v1/admin/metrics'); },
|
||||
{ method: 'GET', path: '/admin/metrics' },
|
||||
function (r) {
|
||||
T.assert(typeof r === 'object', 'expected object');
|
||||
T.assertHasKey(r, 'runtime', 'metrics');
|
||||
T.assertHasKey(r, 'database', 'metrics');
|
||||
}
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
|
||||
// ── Cluster (v0.6.0+) ──
|
||||
// ── Storage ──
|
||||
|
||||
await T.test('admin', 'cluster', 'GET /admin/cluster (raw)', {
|
||||
sdk: function () { return sw.api.get('/admin/cluster'); },
|
||||
raw: { method: 'GET', path: '/admin/cluster' },
|
||||
validate: function (r) {
|
||||
var arr = T.unwrapList(r);
|
||||
T.assert(arr.length >= 0, 'expected cluster node list');
|
||||
}
|
||||
s.test('storage: sw.api.admin.storage.status()', async function (t) {
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.admin.storage.status(); },
|
||||
{ method: 'GET', path: '/admin/storage/status' },
|
||||
function (r) { T.assert(typeof r === 'object', 'expected object'); }
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
|
||||
// ── Vault ──
|
||||
|
||||
s.test('vault: sw.api.admin.vault.status()', async function (t) {
|
||||
if (!window.sw || !sw.isAdmin) { t.warn('SKIP: not admin'); return; }
|
||||
// Vault may not be configured — try raw to check availability
|
||||
var available = false;
|
||||
try {
|
||||
var token = await T.getAuthToken();
|
||||
var resp = await fetch(T.base + '/api/v1/admin/vault/status', {
|
||||
method: 'GET',
|
||||
headers: { 'Authorization': 'Bearer ' + token },
|
||||
credentials: 'same-origin'
|
||||
});
|
||||
available = resp.ok;
|
||||
} catch (e) { /* not available */ }
|
||||
if (!available) { t.warn('SKIP: vault not configured'); return; }
|
||||
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.admin.vault.status(); },
|
||||
{ method: 'GET', path: '/admin/vault/status' },
|
||||
function (r) { T.assert(typeof r === 'object', 'expected object'); }
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
|
||||
// ── Backups (v0.6.1+) ──
|
||||
|
||||
await T.test('admin', 'backups', 'GET /admin/backups (raw)', {
|
||||
sdk: function () { return sw.api.get('/admin/backups'); },
|
||||
raw: { method: 'GET', path: '/admin/backups' },
|
||||
validate: function (r) {
|
||||
var arr = T.unwrapList(r);
|
||||
T.assert(arr.length >= 0, 'expected backup list');
|
||||
}
|
||||
s.test('backups: GET /admin/backups (raw)', async function (t) {
|
||||
var result = await T.dualTest(
|
||||
function () { return sw.api.get('/api/v1/admin/backups'); },
|
||||
{ method: 'GET', path: '/admin/backups' },
|
||||
function (r) {
|
||||
var arr = T.unwrapList(r);
|
||||
T.assert(arr.length >= 0, 'expected backup list');
|
||||
}
|
||||
);
|
||||
if (result.verdict === 'PASS') return;
|
||||
if (result.verdict === 'SDK_BUG') t.assert.ok(false, 'SDK_BUG: ' + result.sdkErr);
|
||||
if (result.verdict === 'ICD_BUG') t.assert.ok(false, 'ICD_BUG: ' + result.rawErr);
|
||||
if (result.verdict === 'SHAPE_BUG') t.warn('SHAPE_BUG: ' + result.sdkErr);
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user