175 lines
5.7 KiB
JavaScript
175 lines
5.7 KiB
JavaScript
|
|
'use strict';
|
||
|
|
|
||
|
|
const test = require('node:test');
|
||
|
|
const assert = require('node:assert/strict');
|
||
|
|
|
||
|
|
const DashboardApi = require('../../src/specificClass.js');
|
||
|
|
const { registerChild } = require('../../src/commands/handlers.js');
|
||
|
|
|
||
|
|
function makeFetch(routes) {
|
||
|
|
const calls = [];
|
||
|
|
const fetchImpl = async (url, opts = {}) => {
|
||
|
|
const method = opts.method || 'GET';
|
||
|
|
const { pathname } = new URL(url);
|
||
|
|
calls.push({ method, pathname, body: opts.body });
|
||
|
|
const r = routes[`${method} ${pathname}`];
|
||
|
|
if (!r) return { ok: false, status: 404, json: async () => ({ message: 'not found' }) };
|
||
|
|
if (typeof r === 'function') return r();
|
||
|
|
return { ok: r.ok ?? true, status: r.status ?? 200, json: async () => r.body };
|
||
|
|
};
|
||
|
|
fetchImpl.calls = calls;
|
||
|
|
return fetchImpl;
|
||
|
|
}
|
||
|
|
|
||
|
|
function api(grafanaConnector = {}) {
|
||
|
|
return new DashboardApi({ grafanaConnector });
|
||
|
|
}
|
||
|
|
|
||
|
|
test('resolveDatasourceUid returns the first influxdb datasource uid', async () => {
|
||
|
|
const a = api();
|
||
|
|
const fetchImpl = makeFetch({
|
||
|
|
'GET /api/datasources': {
|
||
|
|
body: [
|
||
|
|
{ type: 'prometheus', uid: 'p1' },
|
||
|
|
{ type: 'influxdb', uid: 'dfmpjg9jjvym8b', name: 'influxdb' },
|
||
|
|
{ type: 'influxdb', uid: 'second-one' },
|
||
|
|
],
|
||
|
|
},
|
||
|
|
});
|
||
|
|
const uid = await a.resolveDatasourceUid({ fetchImpl });
|
||
|
|
assert.equal(uid, 'dfmpjg9jjvym8b');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('resolveDatasourceUid is cached → second call makes no further fetch', async () => {
|
||
|
|
const a = api();
|
||
|
|
const fetchImpl = makeFetch({
|
||
|
|
'GET /api/datasources': { body: [{ type: 'influxdb', uid: 'u1' }] },
|
||
|
|
});
|
||
|
|
await a.resolveDatasourceUid({ fetchImpl });
|
||
|
|
await a.resolveDatasourceUid({ fetchImpl });
|
||
|
|
assert.equal(fetchImpl.calls.length, 1);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('resolveDatasourceUid returns empty string when no influxdb datasource exists', async () => {
|
||
|
|
const a = api();
|
||
|
|
const fetchImpl = makeFetch({
|
||
|
|
'GET /api/datasources': { body: [{ type: 'prometheus', uid: 'p1' }] },
|
||
|
|
});
|
||
|
|
const uid = await a.resolveDatasourceUid({ fetchImpl });
|
||
|
|
assert.equal(uid, '');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('resolveDatasourceUid: fetch throws → returns empty string (template uid preserved)', async () => {
|
||
|
|
const a = api();
|
||
|
|
const fetchImpl = async () => { throw new Error('ECONNREFUSED'); };
|
||
|
|
const uid = await a.resolveDatasourceUid({ fetchImpl });
|
||
|
|
assert.equal(uid, '');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('resolveDatasourceUid: no fetch available → returns empty string', async () => {
|
||
|
|
const a = api();
|
||
|
|
const uid = await a.resolveDatasourceUid({ fetchImpl: null });
|
||
|
|
assert.equal(uid, '');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('rewriteDatasourceUid: rewrites panel.datasource.uid for influxdb only', () => {
|
||
|
|
const a = api();
|
||
|
|
const dashboard = {
|
||
|
|
panels: [
|
||
|
|
{ datasource: { type: 'influxdb', uid: 'OLD' } },
|
||
|
|
{ datasource: { type: 'grafana', uid: '-- Grafana --' } },
|
||
|
|
],
|
||
|
|
};
|
||
|
|
a.rewriteDatasourceUid(dashboard, 'NEW');
|
||
|
|
assert.equal(dashboard.panels[0].datasource.uid, 'NEW');
|
||
|
|
assert.equal(dashboard.panels[1].datasource.uid, '-- Grafana --');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('rewriteDatasourceUid: rewrites panel.targets[].datasource.uid', () => {
|
||
|
|
const a = api();
|
||
|
|
const dashboard = {
|
||
|
|
panels: [
|
||
|
|
{
|
||
|
|
datasource: { type: 'influxdb', uid: 'OLD' },
|
||
|
|
targets: [
|
||
|
|
{ datasource: { type: 'influxdb', uid: 'OLD' }, query: 'a' },
|
||
|
|
{ datasource: { type: 'influxdb', uid: 'OLD' }, query: 'b' },
|
||
|
|
],
|
||
|
|
},
|
||
|
|
],
|
||
|
|
};
|
||
|
|
a.rewriteDatasourceUid(dashboard, 'NEW');
|
||
|
|
for (const t of dashboard.panels[0].targets) assert.equal(t.datasource.uid, 'NEW');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('rewriteDatasourceUid: descends into nested row panels', () => {
|
||
|
|
const a = api();
|
||
|
|
const dashboard = {
|
||
|
|
panels: [
|
||
|
|
{
|
||
|
|
type: 'row',
|
||
|
|
panels: [
|
||
|
|
{ datasource: { type: 'influxdb', uid: 'OLD' } },
|
||
|
|
],
|
||
|
|
},
|
||
|
|
],
|
||
|
|
};
|
||
|
|
a.rewriteDatasourceUid(dashboard, 'NEW');
|
||
|
|
assert.equal(dashboard.panels[0].panels[0].datasource.uid, 'NEW');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('rewriteDatasourceUid: rewrites templating.list[] influxdb variables', () => {
|
||
|
|
const a = api();
|
||
|
|
const dashboard = {
|
||
|
|
panels: [],
|
||
|
|
templating: {
|
||
|
|
list: [
|
||
|
|
{ type: 'query', datasource: { type: 'influxdb', uid: 'OLD' } },
|
||
|
|
{ type: 'constant', datasource: { type: 'prometheus', uid: 'OLD' } },
|
||
|
|
],
|
||
|
|
},
|
||
|
|
};
|
||
|
|
a.rewriteDatasourceUid(dashboard, 'NEW');
|
||
|
|
assert.equal(dashboard.templating.list[0].datasource.uid, 'NEW');
|
||
|
|
assert.equal(dashboard.templating.list[1].datasource.uid, 'OLD');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('rewriteDatasourceUid: leaves template-variable references alone (${datasource})', () => {
|
||
|
|
const a = api();
|
||
|
|
const dashboard = {
|
||
|
|
panels: [{ datasource: { type: 'influxdb', uid: '${datasource}' } }],
|
||
|
|
};
|
||
|
|
a.rewriteDatasourceUid(dashboard, 'NEW');
|
||
|
|
assert.equal(dashboard.panels[0].datasource.uid, '${datasource}');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('rewriteDatasourceUid: no-op when uid is falsy (preserves template)', () => {
|
||
|
|
const a = api();
|
||
|
|
const dashboard = { panels: [{ datasource: { type: 'influxdb', uid: 'KEEP' } }] };
|
||
|
|
a.rewriteDatasourceUid(dashboard, '');
|
||
|
|
assert.equal(dashboard.panels[0].datasource.uid, 'KEEP');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('emit path rewrites every upsert dashboard with the resolved datasource uid', async () => {
|
||
|
|
const a = api({ folderTitle: 'EVOLV' });
|
||
|
|
a.resolveFolderUid = async () => 'fld';
|
||
|
|
a.resolveDatasourceUid = async () => 'resolved-ds-uid';
|
||
|
|
|
||
|
|
const childSource = {
|
||
|
|
config: { general: { id: 'm1', name: 'Level' }, functionality: { softwareType: 'measurement' } },
|
||
|
|
};
|
||
|
|
const sent = [];
|
||
|
|
const ctx = { node: { id: 'dapi' }, send: (m) => sent.push(m) };
|
||
|
|
await registerChild(a, { payload: childSource }, ctx);
|
||
|
|
|
||
|
|
assert.ok(sent.length >= 1);
|
||
|
|
for (const m of sent) {
|
||
|
|
const panels = m.payload?.dashboard?.panels || [];
|
||
|
|
for (const p of panels) {
|
||
|
|
if (p?.datasource?.type === 'influxdb') {
|
||
|
|
assert.equal(p.datasource.uid, 'resolved-ds-uid');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|