Changeset 0.28.6 (#192)
This commit is contained in:
@@ -124,5 +124,30 @@
|
||||
T.assertStatus(d, 404, 'delete non-existent');
|
||||
});
|
||||
|
||||
// ── Admin broadcast (v0.28.6) ──
|
||||
|
||||
await T.test('crud', 'notifications', 'POST /admin/notifications/broadcast', async function () {
|
||||
var d = await T.apiPost('/admin/notifications/broadcast', {
|
||||
title: 'ICD Test Broadcast',
|
||||
message: 'Automated test broadcast.',
|
||||
level: 'info'
|
||||
});
|
||||
T.assertHasKey(d, 'message', 'broadcast response');
|
||||
T.assertHasKey(d, 'count', 'broadcast response');
|
||||
T.assert(d.count >= 1, 'count should be >= 1');
|
||||
});
|
||||
|
||||
await T.test('crud', 'notifications', 'POST /admin/notifications/broadcast (missing title → 400)', async function () {
|
||||
var token = await T.getAuthToken();
|
||||
var d = await T.authFetch(token, 'POST', '/admin/notifications/broadcast', { message: 'no title' });
|
||||
T.assertStatus(d, 400, 'missing title');
|
||||
});
|
||||
|
||||
await T.test('crud', 'notifications', 'POST /admin/notifications/broadcast (invalid level → 400)', async function () {
|
||||
var token = await T.getAuthToken();
|
||||
var d = await T.authFetch(token, 'POST', '/admin/notifications/broadcast', { title: 'x', message: 'x', level: 'extreme' });
|
||||
T.assertStatus(d, 400, 'invalid level');
|
||||
});
|
||||
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -249,5 +249,66 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ── System functions (v0.28.6) ──
|
||||
|
||||
await T.test('crud', 'tasks', 'GET /admin/system-functions', async function () {
|
||||
var d = await T.apiGet('/admin/system-functions');
|
||||
T.assertHasKey(d, 'data', 'system-functions');
|
||||
T.assert(Array.isArray(d.data), 'data should be array');
|
||||
T.assert(d.data.length >= 4, 'should have at least 4 built-in functions, got ' + d.data.length);
|
||||
var names = d.data.map(function(f) { return f.name; });
|
||||
T.assert(names.indexOf('session_cleanup') >= 0, 'should include session_cleanup');
|
||||
T.assert(names.indexOf('staleness_check') >= 0, 'should include staleness_check');
|
||||
T.assert(names.indexOf('retention_sweep') >= 0, 'should include retention_sweep');
|
||||
T.assert(names.indexOf('health_prune') >= 0, 'should include health_prune');
|
||||
// Verify shape
|
||||
T.assert(typeof d.data[0].name === 'string', 'name should be string');
|
||||
T.assert(typeof d.data[0].description === 'string', 'description should be string');
|
||||
});
|
||||
|
||||
var sysTaskId = null;
|
||||
await T.test('crud', 'tasks', 'POST /tasks (create system task)', async function () {
|
||||
var d = await T.apiPost('/tasks', {
|
||||
name: testTag + '-system-task',
|
||||
task_type: 'system',
|
||||
system_function: 'health_prune',
|
||||
schedule: '0 3 * * *',
|
||||
scope: 'global',
|
||||
});
|
||||
T.assert(d.id, 'should return id');
|
||||
T.assert(d.task_type === 'system', 'task_type should be system');
|
||||
T.assert(d.system_function === 'health_prune', 'system_function should be health_prune');
|
||||
sysTaskId = d.id;
|
||||
T.registerCleanup(function () { if (sysTaskId) return T.safeDelete('/tasks/' + sysTaskId); });
|
||||
});
|
||||
|
||||
if (sysTaskId) {
|
||||
await T.test('crud', 'tasks', 'DELETE /tasks/:id (cleanup system task)', async function () {
|
||||
await T.safeDelete('/tasks/' + sysTaskId);
|
||||
sysTaskId = null;
|
||||
});
|
||||
}
|
||||
|
||||
await T.test('crud', 'tasks', 'POST /tasks (system task — invalid function → 400)', async function () {
|
||||
var token = await T.getAuthToken();
|
||||
var d = await T.authFetch(token, 'POST', '/tasks', {
|
||||
name: 'bad-func',
|
||||
task_type: 'system',
|
||||
system_function: 'nonexistent_func',
|
||||
schedule: '0 3 * * *',
|
||||
});
|
||||
T.assertStatus(d, 400, 'invalid system function');
|
||||
});
|
||||
|
||||
await T.test('crud', 'tasks', 'POST /tasks (system task — missing function → 400)', async function () {
|
||||
var token = await T.getAuthToken();
|
||||
var d = await T.authFetch(token, 'POST', '/tasks', {
|
||||
name: 'no-func',
|
||||
task_type: 'system',
|
||||
schedule: '0 3 * * *',
|
||||
});
|
||||
T.assertStatus(d, 400, 'missing system_function');
|
||||
});
|
||||
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -25,6 +25,49 @@
|
||||
T.assert(Array.isArray(d.data), 'data must be array');
|
||||
});
|
||||
|
||||
// ── POST /git-credentials/generate — server-side keygen (v0.28.6) ──
|
||||
var generatedKeyId = null;
|
||||
await T.test('crud', 'workspaces', 'POST /git-credentials/generate', async function () {
|
||||
var d = await T.apiPost('/git-credentials/generate', { name: 'ICD Test Key' });
|
||||
T.assert(d.id, 'should return id');
|
||||
T.assert(d.auth_type === 'ssh_key', 'auth_type should be ssh_key');
|
||||
T.assert(d.public_key && d.public_key.length > 0, 'should return public_key');
|
||||
T.assert(d.fingerprint && d.fingerprint.startsWith('SHA256:'), 'should return SHA256 fingerprint');
|
||||
T.assert(!d.encrypted_data, 'must NOT expose encrypted_data');
|
||||
T.assert(!d.nonce, 'must NOT expose nonce');
|
||||
generatedKeyId = d.id;
|
||||
T.registerCleanup(function () { if (generatedKeyId) return T.safeDelete('/git-credentials/' + generatedKeyId); });
|
||||
});
|
||||
|
||||
if (generatedKeyId) {
|
||||
await T.test('crud', 'workspaces', 'GET /git-credentials/:id/public-key', async function () {
|
||||
var d = await T.apiGet('/git-credentials/' + generatedKeyId + '/public-key');
|
||||
T.assertHasKey(d, 'public_key', 'public-key response');
|
||||
T.assertHasKey(d, 'fingerprint', 'public-key response');
|
||||
T.assert(d.public_key.length > 0, 'public_key should be non-empty');
|
||||
});
|
||||
|
||||
await T.test('crud', 'workspaces', 'GET /git-credentials (list after generate)', async function () {
|
||||
var d = await T.apiGet('/git-credentials');
|
||||
var found = (d.data || []).find(function (c) { return c.id === generatedKeyId; });
|
||||
T.assert(found, 'generated key should appear in list');
|
||||
T.assert(found.public_key, 'list item should have public_key');
|
||||
T.assert(found.fingerprint, 'list item should have fingerprint');
|
||||
});
|
||||
|
||||
await T.test('crud', 'workspaces', 'DELETE /git-credentials/:id', async function () {
|
||||
var d = await T.apiDelete('/git-credentials/' + generatedKeyId);
|
||||
T.assert(d.deleted === true, 'should return deleted: true');
|
||||
generatedKeyId = null;
|
||||
});
|
||||
}
|
||||
|
||||
await T.test('crud', 'workspaces', 'POST /git-credentials/generate (missing name → 400)', async function () {
|
||||
var token = await T.getAuthToken();
|
||||
var d = await T.authFetch(token, 'POST', '/git-credentials/generate', {});
|
||||
T.assertStatus(d, 400, 'missing name');
|
||||
});
|
||||
|
||||
// ── Workspace CRUD ──
|
||||
var wsId = null;
|
||||
await T.test('crud', 'workspaces', 'POST /workspaces (create)', async function () {
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
S.safeConfig = { id: 'string', name: 'string', provider: 'string', is_active: 'bool', has_key: 'bool' };
|
||||
S.catalogModel = { model_id: 'string', provider: 'string' };
|
||||
S.modelEnabled = { id: 'string', model_id: 'string', display_name: 'string', model_type: 'string', source: 'string', provider_config_id: 'string', provider_name: 'string', provider_type: 'string', capabilities: 'object', scope: 'string', is_persona: 'bool', hidden: 'bool' };
|
||||
S.modelPreference = { id: 'string', user_id: 'string', model_id: 'string', hidden: 'bool', sort_order: 'number', created_at: 'string', updated_at: 'string' };
|
||||
S.modelPreference = { id: 'string', user_id: 'string', model_id: 'string', provider_config_id: 'string', hidden: 'bool', sort_order: 'number', created_at: 'string', updated_at: 'string' };
|
||||
S.task = { id: 'string', name: 'string', task_type: 'string', schedule: 'string', is_active: 'bool', created_at: 'string' };
|
||||
S.taskFull = { id: 'string', owner_id: 'string', name: 'string', task_type: 'string', scope: 'string', schedule: 'string', timezone: 'string', is_active: 'bool', max_tokens: 'number', max_tool_calls: 'number', max_wall_clock: 'number', output_mode: 'string', run_count: 'number', created_at: 'string', updated_at: 'string' };
|
||||
S.taskRun = { id: 'string', task_id: 'string', status: 'string', started_at: 'string' };
|
||||
|
||||
Reference in New Issue
Block a user