The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/dashboard/specs/dashboard_model_specs.ts

448 lines
13 KiB

import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
import _ from 'lodash';
import {DashboardModel} from '../model';
describe('DashboardModel', function() {
describe('when creating new dashboard model defaults only', function() {
var model;
beforeEach(function() {
model = new DashboardModel({}, {});
});
it('should have title', function() {
expect(model.title).to.be('No Title');
});
it('should have meta', function() {
expect(model.meta.canSave).to.be(true);
expect(model.meta.canShare).to.be(true);
});
it('should have default properties', function() {
expect(model.rows.length).to.be(0);
});
});
describe('when getting next panel id', function() {
var model;
beforeEach(function() {
model = new DashboardModel({
rows: [{ panels: [{ id: 5 }]}]
});
});
it('should return max id + 1', function() {
expect(model.getNextPanelId()).to.be(6);
});
});
describe('getSaveModelClone', function() {
it('should sort keys', () => {
var model = new DashboardModel({});
var saveModel = model.getSaveModelClone();
var keys = _.keys(saveModel);
expect(keys[0]).to.be('addEmptyRow');
expect(keys[1]).to.be('addPanel');
});
});
describe('row and panel manipulation', function() {
var dashboard;
beforeEach(function() {
dashboard = new DashboardModel({});
});
it('adding default should split span in half', function() {
dashboard.addEmptyRow();
dashboard.rows[0].addPanel({span: 12});
dashboard.rows[0].addPanel({span: 12});
expect(dashboard.rows[0].panels[0].span).to.be(6);
expect(dashboard.rows[0].panels[1].span).to.be(6);
});
it('duplicate panel should try to add it to same row', function() {
var panel = { span: 4, attr: '123', id: 10 };
dashboard.addEmptyRow();
dashboard.rows[0].addPanel(panel);
dashboard.duplicatePanel(panel, dashboard.rows[0]);
expect(dashboard.rows[0].panels[0].span).to.be(4);
expect(dashboard.rows[0].panels[1].span).to.be(4);
expect(dashboard.rows[0].panels[1].attr).to.be('123');
expect(dashboard.rows[0].panels[1].id).to.be(11);
});
it('duplicate panel should remove repeat data', function() {
var panel = { span: 4, attr: '123', id: 10, repeat: 'asd', scopedVars: { test: 'asd' }};
dashboard.addEmptyRow();
dashboard.rows[0].addPanel(panel);
dashboard.duplicatePanel(panel, dashboard.rows[0]);
expect(dashboard.rows[0].panels[1].repeat).to.be(undefined);
expect(dashboard.rows[0].panels[1].scopedVars).to.be(undefined);
});
});
describe('when creating dashboard with old schema', function() {
var model;
var graph;
var singlestat;
var table;
beforeEach(function() {
model = new DashboardModel({
services: { filter: { time: { from: 'now-1d', to: 'now'}, list: [{}] }},
pulldowns: [
{type: 'filtering', enable: true},
{type: 'annotations', enable: true, annotations: [{name: 'old'}]}
],
rows: [
{
panels: [
{
type: 'graph', legend: true, aliasYAxis: { test: 2 },
y_formats: ['kbyte', 'ms'],
grid: {
min: 1,
max: 10,
rightMin: 5,
rightMax: 15,
leftLogBase: 1,
rightLogBase: 2,
threshold1: 200,
threshold2: 400,
threshold1Color: 'yellow',
threshold2Color: 'red',
},
leftYAxisLabel: 'left label',
targets: [{refId: 'A'}, {}],
},
{
type: 'singlestat', legend: true, thresholds: '10,20,30', aliasYAxis: { test: 2 }, grid: { min: 1, max: 10 },
targets: [{refId: 'A'}, {}],
},
{
type: 'table', legend: true, styles: [{ thresholds: ["10", "20", "30"]}, { thresholds: ["100", "200", "300"]}],
targets: [{refId: 'A'}, {}],
}
]
}
]
});
graph = model.rows[0].panels[0];
singlestat = model.rows[0].panels[1];
table = model.rows[0].panels[2];
});
it('should have title', function() {
expect(model.title).to.be('No Title');
});
it('should have panel id', function() {
expect(graph.id).to.be(1);
});
it('should move time and filtering list', function() {
expect(model.time.from).to.be('now-1d');
expect(model.templating.list[0].allFormat).to.be('glob');
});
it('graphite panel should change name too graph', function() {
expect(graph.type).to.be('graph');
});
it('single stat panel should have two thresholds', function() {
expect(singlestat.thresholds).to.be('20,30');
});
it('queries without refId should get it', function() {
expect(graph.targets[1].refId).to.be('B');
});
it('update legend setting', function() {
expect(graph.legend.show).to.be(true);
});
it('move aliasYAxis to series override', function() {
expect(graph.seriesOverrides[0].alias).to.be("test");
expect(graph.seriesOverrides[0].yaxis).to.be(2);
});
it('should move pulldowns to new schema', function() {
expect(model.annotations.list[0].name).to.be('old');
});
it('table panel should only have two thresholds values', function() {
expect(table.styles[0].thresholds[0]).to.be("20");
expect(table.styles[0].thresholds[1]).to.be("30");
expect(table.styles[1].thresholds[0]).to.be("200");
expect(table.styles[1].thresholds[1]).to.be("300");
});
it('graph grid to yaxes options', function() {
expect(graph.yaxes[0].min).to.be(1);
expect(graph.yaxes[0].max).to.be(10);
expect(graph.yaxes[0].format).to.be('kbyte');
expect(graph.yaxes[0].label).to.be('left label');
expect(graph.yaxes[0].logBase).to.be(1);
expect(graph.yaxes[1].min).to.be(5);
expect(graph.yaxes[1].max).to.be(15);
expect(graph.yaxes[1].format).to.be('ms');
expect(graph.yaxes[1].logBase).to.be(2);
expect(graph.grid.rightMax).to.be(undefined);
expect(graph.grid.rightLogBase).to.be(undefined);
expect(graph.y_formats).to.be(undefined);
});
it('dashboard schema version should be set to latest', function() {
expect(model.schemaVersion).to.be(14);
});
it('graph thresholds should be migrated', function() {
expect(graph.thresholds.length).to.be(2);
expect(graph.thresholds[0].op).to.be('gt');
expect(graph.thresholds[0].value).to.be(200);
expect(graph.thresholds[0].fillColor).to.be('yellow');
expect(graph.thresholds[1].value).to.be(400);
expect(graph.thresholds[1].fillColor).to.be('red');
});
});
describe('when creating dashboard model with missing list for annoations or templating', function() {
var model;
beforeEach(function() {
model = new DashboardModel({
annotations: {
enable: true,
},
templating: {
enable: true
}
});
});
it('should add empty list', function() {
expect(model.annotations.list.length).to.be(0);
expect(model.templating.list.length).to.be(0);
});
});
describe('Given editable false dashboard', function() {
var model;
beforeEach(function() {
model = new DashboardModel({editable: false});
});
it('Should set meta canEdit and canSave to false', function() {
expect(model.meta.canSave).to.be(false);
expect(model.meta.canEdit).to.be(false);
});
it('getSaveModelClone should remove meta', function() {
var clone = model.getSaveModelClone();
expect(clone.meta).to.be(undefined);
});
});
describe('when loading dashboard with old influxdb query schema', function() {
var model;
var target;
beforeEach(function() {
model = new DashboardModel({
rows: [{
panels: [{
type: 'graph',
grid: {},
yaxes: [{}, {}],
targets: [{
"alias": "$tag_datacenter $tag_source $col",
"column": "value",
"measurement": "logins.count",
"fields": [
{
"func": "mean",
"name": "value",
"mathExpr": "*2",
"asExpr": "value"
},
{
"name": "one-minute",
"func": "mean",
"mathExpr": "*3",
"asExpr": "one-minute"
}
],
"tags": [],
"fill": "previous",
"function": "mean",
"groupBy": [
{
"interval": "auto",
"type": "time"
},
{
"key": "source",
"type": "tag"
},
{
"type": "tag",
"key": "datacenter"
}
],
}]
}]
}]
});
target = model.rows[0].panels[0].targets[0];
});
it('should update query schema', function() {
expect(target.fields).to.be(undefined);
expect(target.select.length).to.be(2);
expect(target.select[0].length).to.be(4);
expect(target.select[0][0].type).to.be('field');
expect(target.select[0][1].type).to.be('mean');
expect(target.select[0][2].type).to.be('math');
expect(target.select[0][3].type).to.be('alias');
});
});
describe('when creating dashboard model with missing list for annoations or templating', function() {
var model;
beforeEach(function() {
model = new DashboardModel({
annotations: {
enable: true,
},
templating: {
enable: true
}
});
});
it('should add empty list', function() {
expect(model.annotations.list.length).to.be(0);
expect(model.templating.list.length).to.be(0);
});
});
describe('Formatting epoch timestamp when timezone is set as utc', function() {
var dashboard;
beforeEach(function() {
dashboard = new DashboardModel({timezone: 'utc'});
});
it('Should format timestamp with second resolution by default', function() {
expect(dashboard.formatDate(1234567890000)).to.be('2009-02-13 23:31:30');
});
it('Should format timestamp with second resolution even if second format is passed as parameter', function() {
expect(dashboard.formatDate(1234567890007,'YYYY-MM-DD HH:mm:ss')).to.be('2009-02-13 23:31:30');
});
it('Should format timestamp with millisecond resolution if format is passed as parameter', function() {
expect(dashboard.formatDate(1234567890007,'YYYY-MM-DD HH:mm:ss.SSS')).to.be('2009-02-13 23:31:30.007');
});
});
describe('updateSubmenuVisibility with empty lists', function() {
var model;
beforeEach(function() {
model = new DashboardModel({});
model.updateSubmenuVisibility();
});
it('should not enable submmenu', function() {
expect(model.meta.submenuEnabled).to.be(false);
});
});
describe('updateSubmenuVisibility with annotation', function() {
var model;
beforeEach(function() {
model = new DashboardModel({
annotations: {
list: [{}]
}
});
model.updateSubmenuVisibility();
});
it('should enable submmenu', function() {
expect(model.meta.submenuEnabled).to.be(true);
});
});
describe('updateSubmenuVisibility with template var', function() {
var model;
beforeEach(function() {
model = new DashboardModel({
templating: {
list: [{}]
}
});
model.updateSubmenuVisibility();
});
it('should enable submmenu', function() {
expect(model.meta.submenuEnabled).to.be(true);
});
});
describe('updateSubmenuVisibility with hidden template var', function() {
var model;
beforeEach(function() {
model = new DashboardModel({
templating: {
list: [{hide: 2}]
}
});
model.updateSubmenuVisibility();
});
it('should not enable submmenu', function() {
expect(model.meta.submenuEnabled).to.be(false);
});
});
describe('updateSubmenuVisibility with hidden annotation toggle', function() {
var model;
beforeEach(function() {
model = new DashboardModel({
annotations: {
list: [{hide: true}]
}
});
model.updateSubmenuVisibility();
});
it('should not enable submmenu', function() {
expect(model.meta.submenuEnabled).to.be(false);
});
});
});