Commit 4aa227dd by Torkel Ödegaard Committed by GitHub

[Tech]: Start migrating to Jest for tests (#9610)

* tech: investigating karma + jest mix

* tech: migrating tests to jest

* tech: moved anoter test file to jest

* test: migrated two more test files to jest

* test: updated readme and made test fail to verify that it causes CI build failure

* tech: added code coverage for jest tests

* tech: testing codecov coverage

* tech: migrated more tests

* tech: migrated template srv to typescript and the tests to jest

* tech: minor build fix

* tech: build fixes

* build: another attempt at fixing go test with coverage
parent c4365e22
......@@ -12,6 +12,8 @@ awsconfig
/tmp
vendor/phantomjs/phantomjs
vendor/phantomjs/phantomjs.exe
profile.out
coverage.txt
docs/AWS_S3_BUCKET
docs/GIT_BRANCH
......
......@@ -22,9 +22,10 @@ module.exports = function (grunt) {
}
}
config.coverage = grunt.option('coverage');
config.phjs = grunt.option('phjsToRelease');
config.pkg.version = grunt.option('pkgVer') || config.pkg.version;
console.log('Version', config.pkg.version);
// load plugins
......
[Grafana](https://grafana.com) [![Circle CI](https://circleci.com/gh/grafana/grafana.svg?style=svg)](https://circleci.com/gh/grafana/grafana) [![Go Report Card](https://goreportcard.com/badge/github.com/grafana/grafana)](https://goreportcard.com/report/github.com/grafana/grafana)
[Grafana](https://grafana.com) [![Circle CI](https://circleci.com/gh/grafana/grafana.svg?style=svg)](https://circleci.com/gh/grafana/grafana) [![Go Report Card](https://goreportcard.com/badge/github.com/grafana/grafana)](https://goreportcard.com/report/github.com/grafana/grafana) [![codecov](https://codecov.io/gh/grafana/grafana/branch/master/graph/badge.svg)](https://codecov.io/gh/grafana/grafana)
================
[Website](https://grafana.com) |
[Twitter](https://twitter.com/grafana) |
......@@ -81,6 +81,20 @@ You only need to add the options you want to override. Config files are applied
In your custom.ini uncomment (remove the leading `;`) sign. And set `app_mode = development`.
### Running tests
- You can run backend Golang tests using "go test ./pkg/...".
- Execute all frontend tests with "npm run test"
Writing & watching frontend tests (we have two test runners)
- jest for all new tests that do not require browser context (React+more)
- Start watcher: `npm run jest`
- Jest will run all test files that end with the name ".jest.ts"
- karma + mocha is used for testing angularjs components. We do want to migrate these test to jest over time (if possible).
- Start watcher: `npm run karma`
- Karma+Mocha runs all files that end with the name "_specs.ts".
## Contribute
If you have any idea for an improvement or found a bug do not hesitate to open an issue.
......
......@@ -84,6 +84,20 @@ bra run
You'll also need to run `npm run watch` to watch for changes to the front-end (typescript, html, sass)
### Running tests
- You can run backend Golang tests using "go test ./pkg/...".
- Execute all frontend tests with "npm run test"
Writing & watching frontend tests (we have two test runners)
- jest for all new tests that do not require browser context (React+more)
- Start watcher: `npm run jest`
- Jest will run all test files that end with the name ".jest.ts"
- karma + mocha is used for testing angularjs components. We do want to migrate these test to jest over time (if possible).
- Start watcher: `npm run karma`
- Karma+Mocha runs all files that end with the name "_specs.ts".
## Creating optimized release packages
This step builds linux packages and requires that fpm is installed. Install fpm via `gem install fpm`.
......
module.exports = {
verbose: false,
"transform": {
"^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"moduleDirectories": ["<rootDir>node_modules", "<rootDir>/public"],
"roots": [
"<rootDir>/public"
],
"testRegex": "(\\.|/)(jest)\\.(jsx?|tsx?)$",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json"
],
"setupFiles": [
"./public/test/jest-shim.ts",
"./public/test/jest-setup.ts"
]
};
......@@ -12,6 +12,7 @@
"devDependencies": {
"@types/d3": "^4.10.1",
"@types/enzyme": "^2.8.9",
"@types/jest": "^21.1.4",
"@types/node": "^8.0.31",
"@types/react": "^16.0.5",
"@types/react-dom": "^15.5.4",
......@@ -22,8 +23,8 @@
"babel-loader": "^7.1.2",
"babel-preset-es2015": "^6.24.1",
"css-loader": "^0.28.7",
"enzyme": "^3.0.0",
"enzyme-adapter-react-16": "^1.0.0",
"enzyme": "^3.1.0",
"enzyme-adapter-react-16": "^1.0.1",
"es6-promise": "^3.0.2",
"es6-shim": "^0.35.3",
"expect.js": "~0.2.0",
......@@ -53,11 +54,11 @@
"html-loader": "^0.5.1",
"html-webpack-plugin": "^2.30.1",
"husky": "^0.14.3",
"jest": "^21.2.1",
"jshint-stylish": "~2.2.1",
"json-loader": "^0.5.7",
"karma": "1.7.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage": "1.1.1",
"karma-expect": "~1.1.3",
"karma-mocha": "~1.3.0",
"karma-phantomjs-launcher": "1.0.4",
......@@ -82,6 +83,7 @@
"sinon": "1.17.6",
"systemjs": "0.20.19",
"systemjs-plugin-css": "^0.1.36",
"ts-jest": "^21.1.3",
"ts-loader": "^2.3.7",
"tslint": "^5.7.0",
"tslint-loader": "^3.5.3",
......@@ -97,8 +99,10 @@
"watch": "./node_modules/.bin/webpack --progress --colors --watch --config scripts/webpack/webpack.dev.js",
"build": "./node_modules/.bin/grunt build",
"test": "./node_modules/.bin/grunt test",
"test-ci": "./node_modules/.bin/grunt test --coverage=true",
"lint": "./node_modules/.bin/tslint -c tslint.json --project tsconfig.json --type-check",
"watch-test": "./node_modules/grunt-cli/bin/grunt karma:dev"
"karma": "./node_modules/grunt-cli/bin/grunt karma:dev",
"jest": "./node_modules/jest-cli/bin/jest --notify --watch"
},
"license": "Apache-2.0",
"dependencies": {
......
import { react2AngularDirective } from 'app/core/utils/react2angular';
import { PasswordStrength } from './ui/PasswordStrength';
export function registerAngularDirectives() {
react2AngularDirective('passwordStrength', PasswordStrength, ['password']);
}
......@@ -43,9 +43,11 @@ import {assignModelProperties} from './utils/model_utils';
import {contextSrv} from './services/context_srv';
import {KeybindingSrv} from './services/keybindingSrv';
import {helpModal} from './components/help/help';
import {PasswordStrength} from './components/PasswordStrength';
import {JsonExplorer} from './components/json_explorer/json_explorer';
import {NavModelSrv, NavModel} from './nav_model_srv';
import {registerAngularDirectives} from './angular_wrappers';
registerAngularDirectives();
export {
arrayJoin,
......@@ -71,5 +73,4 @@ export {
JsonExplorer,
NavModelSrv,
NavModel,
PasswordStrength,
};
......@@ -7,6 +7,8 @@ define([
function (angular, require, coreModule, kbn) {
'use strict';
kbn = kbn.default;
coreModule.default.directive('tip', function($compile) {
return {
restrict: 'E',
......
define([
'../core_module',
'app/core/utils/kbn',
'app/core/utils/rangeutil',
],
function (coreModule, kbn, rangeUtil) {
function (coreModule, rangeUtil) {
'use strict';
coreModule.default.directive('ngModelOnblur', function() {
......
import React from 'react';
import {describe, it, expect} from 'test/lib/common';
import {shallow} from 'enzyme';
import {PasswordStrength} from '../components/PasswordStrength';
import {PasswordStrength} from '../ui/PasswordStrength';
describe('PasswordStrength', () => {
it('should have class bad if length below 4', () => {
const wrapper = shallow(<PasswordStrength password="asd" />);
expect(wrapper.find(".password-strength-bad")).to.have.length(1);
expect(wrapper.find(".password-strength-bad")).toHaveLength(1);
});
it('should have class ok if length below 8', () => {
const wrapper = shallow(<PasswordStrength password="asdasd" />);
expect(wrapper.find(".password-strength-ok")).to.have.length(1);
expect(wrapper.find(".password-strength-ok")).toHaveLength(1);
});
it('should have class good if length above 8', () => {
const wrapper = shallow(<PasswordStrength password="asdaasdda" />);
expect(wrapper.find(".password-strength-good")).to.have.length(1);
expect(wrapper.find(".password-strength-good")).toHaveLength(1);
});
});
......
import {describe, beforeEach, afterEach, it, sinon, expect} from 'test/lib/common';
import sinon from 'sinon';
import * as dateMath from 'app/core/utils/datemath';
import moment from 'moment';
......@@ -13,25 +13,25 @@ describe("DateMath", () => {
describe('errors', () => {
it('should return undefined if passed something falsy', () => {
expect(dateMath.parse(false)).to.be(undefined);
expect(dateMath.parse(false)).toBe(undefined);
});
it('should return undefined if I pass an operator besides [+-/]', () => {
expect(dateMath.parse('now&1d')).to.be(undefined);
expect(dateMath.parse('now&1d')).toBe(undefined);
});
it('should return undefined if I pass a unit besides' + spans.toString(), () => {
expect(dateMath.parse('now+5f')).to.be(undefined);
expect(dateMath.parse('now+5f')).toBe(undefined);
});
it('should return undefined if rounding unit is not 1', () => {
expect(dateMath.parse('now/2y')).to.be(undefined);
expect(dateMath.parse('now/0.5y')).to.be(undefined);
expect(dateMath.parse('now/2y')).toBe(undefined);
expect(dateMath.parse('now/0.5y')).toBe(undefined);
});
it('should not go into an infinite loop when missing a unit', () => {
expect(dateMath.parse('now-0')).to.be(undefined);
expect(dateMath.parse('now-00')).to.be(undefined);
expect(dateMath.parse('now-0')).toBe(undefined);
expect(dateMath.parse('now-00')).toBe(undefined);
});
});
......@@ -43,7 +43,7 @@ describe("DateMath", () => {
expected.setMilliseconds(0);
var startOfDay = dateMath.parse('now/d', false).valueOf();
expect(startOfDay).to.be(expected.getTime());
expect(startOfDay).toBe(expected.getTime());
});
it("now/d on a utc dashboard should be start of the current day in UTC time", () => {
......@@ -51,7 +51,7 @@ describe("DateMath", () => {
var expected = new Date(Date.UTC(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0));
var startOfDay = dateMath.parse('now/d', false, 'utc').valueOf();
expect(startOfDay).to.be(expected.getTime());
expect(startOfDay).toBe(expected.getTime());
});
describe('subtraction', () => {
......@@ -69,11 +69,11 @@ describe("DateMath", () => {
var thenEx = anchor + '||-5' + span;
it('should return 5' + span + ' ago', () => {
expect(dateMath.parse(nowEx).format(format)).to.eql(now.subtract(5, span).format(format));
expect(dateMath.parse(nowEx).format(format)).toEqual(now.subtract(5, span).format(format));
});
it('should return 5' + span + ' before ' + anchor, () => {
expect(dateMath.parse(thenEx).format(format)).to.eql(anchored.subtract(5, span).format(format));
expect(dateMath.parse(thenEx).format(format)).toEqual(anchored.subtract(5, span).format(format));
});
});
......@@ -94,11 +94,11 @@ describe("DateMath", () => {
_.each(spans, (span) => {
it('should round now to the beginning of the ' + span, function () {
expect(dateMath.parse('now/' + span).format(format)).to.eql(now.startOf(span).format(format));
expect(dateMath.parse('now/' + span).format(format)).toEqual(now.startOf(span).format(format));
});
it('should round now to the end of the ' + span, function () {
expect(dateMath.parse('now/' + span, true).format(format)).to.eql(now.endOf(span).format(format));
expect(dateMath.parse('now/' + span, true).format(format)).toEqual(now.endOf(span).format(format));
});
});
......@@ -109,27 +109,27 @@ describe("DateMath", () => {
describe('isValid', () => {
it('should return false when invalid date text', () => {
expect(dateMath.isValid('asd')).to.be(false);
expect(dateMath.isValid('asd')).toBe(false);
});
it('should return true when valid date text', () => {
expect(dateMath.isValid('now-1h')).to.be(true);
expect(dateMath.isValid('now-1h')).toBe(true);
});
});
describe('relative time to date parsing', function() {
it('should handle negative time', function() {
var date = dateMath.parseDateMath('-2d', moment([2014, 1, 5]));
expect(date.valueOf()).to.equal(moment([2014, 1, 3]).valueOf());
expect(date.valueOf()).toEqual(moment([2014, 1, 3]).valueOf());
});
it('should handle multiple math expressions', function() {
var date = dateMath.parseDateMath('-2d-6h', moment([2014, 1, 5]));
expect(date.valueOf()).to.equal(moment([2014, 1, 2, 18]).valueOf());
expect(date.valueOf()).toEqual(moment([2014, 1, 2, 18]).valueOf());
});
it('should return false when invalid expression', function() {
var date = dateMath.parseDateMath('2', moment([2014, 1, 5]));
expect(date).to.equal(undefined);
expect(date).toEqual(undefined);
});
});
......
import {describe, it, expect} from 'test/lib/common';
import {Emitter} from 'app/core/core';
import {Emitter} from '../utils/emitter';
describe("Emitter", () => {
......@@ -20,8 +18,8 @@ describe("Emitter", () => {
events.emit('test', null);
expect(sub1Called).to.be(true);
expect(sub2Called).to.be(true);
expect(sub1Called).toBe(true);
expect(sub2Called).toBe(true);
});
it('when subscribing twice', () => {
......@@ -37,7 +35,7 @@ describe("Emitter", () => {
events.emit('test', null);
expect(sub1Called).to.be(2);
expect(sub1Called).toBe(2);
});
it('should handle errors', () => {
......@@ -57,8 +55,8 @@ describe("Emitter", () => {
try { events.emit('test', null); } catch (_) { }
try { events.emit('test', null); } catch (_) {}
expect(sub1Called).to.be(2);
expect(sub2Called).to.be(0);
expect(sub1Called).toBe(2);
expect(sub2Called).toBe(0);
});
});
});
......
import {describe, it, expect} from 'test/lib/common';
import flatten from 'app/core/utils/flatten';
describe("flatten", () => {
......@@ -15,9 +13,9 @@ describe("flatten", () => {
}
}, null);
expect(flattened['level1']).to.be('level1-value');
expect(flattened['deeper.level2']).to.be('level2-value');
expect(flattened['deeper.deeper.level3']).to.be('level3-value');
expect(flattened['level1']).toBe('level1-value');
expect(flattened['deeper.level2']).toBe('level2-value');
expect(flattened['deeper.deeper.level3']).toBe('level3-value');
});
});
......
import {describe, it, expect} from 'test/lib/common';
import * as rangeUtil from 'app/core/utils/rangeutil';
import _ from 'lodash';
import moment from 'moment';
......@@ -9,100 +7,100 @@ describe("rangeUtil", () => {
describe("Can get range grouped list of ranges", () => {
it('when custom settings should return default range list', () => {
var groups = rangeUtil.getRelativeTimesList({time_options: []}, 'Last 5 minutes');
expect(_.keys(groups).length).to.be(4);
expect(groups[3][0].active).to.be(true);
expect(_.keys(groups).length).toBe(4);
expect(groups[3][0].active).toBe(true);
});
});
describe("Can get range text described", () => {
it('should handle simple old expression with only amount and unit', () => {
var info = rangeUtil.describeTextRange('5m');
expect(info.display).to.be('Last 5 minutes');
expect(info.display).toBe('Last 5 minutes');
});
it('should have singular when amount is 1', () => {
var info = rangeUtil.describeTextRange('1h');
expect(info.display).to.be('Last 1 hour');
expect(info.display).toBe('Last 1 hour');
});
it('should handle non default amount', () => {
var info = rangeUtil.describeTextRange('13h');
expect(info.display).to.be('Last 13 hours');
expect(info.from).to.be('now-13h');
expect(info.display).toBe('Last 13 hours');
expect(info.from).toBe('now-13h');
});
it('should handle non default future amount', () => {
var info = rangeUtil.describeTextRange('+3h');
expect(info.display).to.be('Next 3 hours');
expect(info.from).to.be('now');
expect(info.to).to.be('now+3h');
expect(info.display).toBe('Next 3 hours');
expect(info.from).toBe('now');
expect(info.to).toBe('now+3h');
});
it('should handle now/d', () => {
var info = rangeUtil.describeTextRange('now/d');
expect(info.display).to.be('Today so far');
expect(info.display).toBe('Today so far');
});
it('should handle now/w', () => {
var info = rangeUtil.describeTextRange('now/w');
expect(info.display).to.be('This week so far');
expect(info.display).toBe('This week so far');
});
it('should handle now/M', () => {
var info = rangeUtil.describeTextRange('now/M');
expect(info.display).to.be('This month so far');
expect(info.display).toBe('This month so far');
});
it('should handle now/y', () => {
var info = rangeUtil.describeTextRange('now/y');
expect(info.display).to.be('This year so far');
expect(info.display).toBe('This year so far');
});
});
describe("Can get date range described", () => {
it('Date range with simple ranges', () => {
var text = rangeUtil.describeTimeRange({from: 'now-1h', to: 'now'});
expect(text).to.be('Last 1 hour');
expect(text).toBe('Last 1 hour');
});
it('Date range with rounding ranges', () => {
var text = rangeUtil.describeTimeRange({from: 'now/d+6h', to: 'now'});
expect(text).to.be('now/d+6h to now');
expect(text).toBe('now/d+6h to now');
});
it('Date range with absolute to now', () => {
var text = rangeUtil.describeTimeRange({from: moment([2014,10,10,2,3,4]), to: 'now'});
expect(text).to.be('Nov 10, 2014 02:03:04 to a few seconds ago');
expect(text).toBe('Nov 10, 2014 02:03:04 to a few seconds ago');
});
it('Date range with absolute to relative', () => {
var text = rangeUtil.describeTimeRange({from: moment([2014,10,10,2,3,4]), to: 'now-1d'});
expect(text).to.be('Nov 10, 2014 02:03:04 to a day ago');
expect(text).toBe('Nov 10, 2014 02:03:04 to a day ago');
});
it('Date range with relative to absolute', () => {
var text = rangeUtil.describeTimeRange({from: 'now-7d', to: moment([2014,10,10,2,3,4])});
expect(text).to.be('7 days ago to Nov 10, 2014 02:03:04');
expect(text).toBe('7 days ago to Nov 10, 2014 02:03:04');
});
it('Date range with non matching default ranges', () => {
var text = rangeUtil.describeTimeRange({from: 'now-13h', to: 'now'});
expect(text).to.be('Last 13 hours');
expect(text).toBe('Last 13 hours');
});
it('Date range with from and to both are in now-* format', () => {
var text = rangeUtil.describeTimeRange({from: 'now-6h', to: 'now-3h'});
expect(text).to.be('now-6h to now-3h');
expect(text).toBe('now-6h to now-3h');
});
it('Date range with from and to both are either in now-* or now/* format', () => {
var text = rangeUtil.describeTimeRange({from: 'now/d+6h', to: 'now-3h'});
expect(text).to.be('now/d+6h to now-3h');
expect(text).toBe('now/d+6h to now-3h');
});
it('Date range with from and to both are either in now-* or now+* format', () => {
var text = rangeUtil.describeTimeRange({from: 'now-6h', to: 'now+1h'});
expect(text).to.be('now-6h to now+1h');
expect(text).toBe('now-6h to now+1h');
});
});
......
import {describe, beforeEach, it, expect} from 'test/lib/common';
import TableModel from 'app/core/table_model';
describe('when sorting table desc', () => {
......@@ -16,14 +14,14 @@ describe('when sorting table desc', () => {
});
it('should sort by time', () => {
expect(table.rows[0][0]).to.be(105);
expect(table.rows[1][0]).to.be(103);
expect(table.rows[2][0]).to.be(100);
expect(table.rows[0][0]).toBe(105);
expect(table.rows[1][0]).toBe(103);
expect(table.rows[2][0]).toBe(100);
});
it ('should mark column being sorted', () => {
expect(table.columns[0].sort).to.be(true);
expect(table.columns[0].desc).to.be(true);
expect(table.columns[0].sort).toBe(true);
expect(table.columns[0].desc).toBe(true);
});
});
......@@ -42,9 +40,9 @@ describe('when sorting table asc', () => {
});
it('should sort by time', () => {
expect(table.rows[0][1]).to.be(10);
expect(table.rows[1][1]).to.be(11);
expect(table.rows[2][1]).to.be(15);
expect(table.rows[0][1]).toBe(10);
expect(table.rows[1][1]).toBe(11);
expect(table.rows[2][1]).toBe(15);
});
});
......
import {describe, beforeEach, it, expect} from 'test/lib/common';
import TimeSeries from 'app/core/time_series2';
describe("TimeSeries", function() {
......@@ -19,14 +18,14 @@ describe("TimeSeries", function() {
it('with connected style, should ignore nulls', function() {
series = new TimeSeries(testData);
points = series.getFlotPairs('connected', yAxisFormats);
expect(points.length).to.be(3);
expect(points.length).toBe(3);
});
it('with null as zero style, should replace nulls with zero', function() {
series = new TimeSeries(testData);
points = series.getFlotPairs('null as zero', yAxisFormats);
expect(points.length).to.be(4);
expect(points[1][1]).to.be(0);
expect(points.length).toBe(4);
expect(points[1][1]).toBe(0);
});
it('if last is null current should pick next to last', function() {
......@@ -34,7 +33,7 @@ describe("TimeSeries", function() {
datapoints: [[10,1], [null, 2]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.current).to.be(10);
expect(series.stats.current).toBe(10);
});
it('max value should work for negative values', function() {
......@@ -42,13 +41,13 @@ describe("TimeSeries", function() {
datapoints: [[-10,1], [-4, 2]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.max).to.be(-4);
expect(series.stats.max).toBe(-4);
});
it('average value should ignore nulls', function() {
series = new TimeSeries(testData);
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.avg).to.be(6.333333333333333);
expect(series.stats.avg).toBe(6.333333333333333);
});
it('the delta value should account for nulls', function() {
......@@ -56,7 +55,7 @@ describe("TimeSeries", function() {
datapoints: [[1,2],[3,3],[null,4],[10,5],[15,6]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.delta).to.be(14);
expect(series.stats.delta).toBe(14);
});
it('the delta value should account for nulls on first', function() {
......@@ -64,7 +63,7 @@ describe("TimeSeries", function() {
datapoints: [[null,2],[1,3],[10,4],[15,5]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.delta).to.be(14);
expect(series.stats.delta).toBe(14);
});
it('the delta value should account for nulls on last', function() {
......@@ -72,7 +71,7 @@ describe("TimeSeries", function() {
datapoints: [[1,2],[5,3],[10,4],[null,5]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.delta).to.be(9);
expect(series.stats.delta).toBe(9);
});
it('the delta value should account for resets', function() {
......@@ -80,7 +79,7 @@ describe("TimeSeries", function() {
datapoints: [[1,2],[5,3],[10,4],[0,5],[10,6]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.delta).to.be(19);
expect(series.stats.delta).toBe(19);
});
it('the delta value should account for resets on last', function() {
......@@ -88,30 +87,30 @@ describe("TimeSeries", function() {
datapoints: [[1,2],[2,3],[10,4],[8,5]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.delta).to.be(17);
expect(series.stats.delta).toBe(17);
});
it('the range value should be max - min', function() {
series = new TimeSeries(testData);
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.range).to.be(9);
expect(series.stats.range).toBe(9);
});
it('first value should ingone nulls', function() {
series = new TimeSeries(testData);
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.first).to.be(1);
expect(series.stats.first).toBe(1);
series = new TimeSeries({
datapoints: [[null,2],[1,3],[10,4],[8,5]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.first).to.be(1);
expect(series.stats.first).toBe(1);
});
it('with null as zero style, average value should treat nulls as 0', function() {
series = new TimeSeries(testData);
series.getFlotPairs('null as zero', yAxisFormats);
expect(series.stats.avg).to.be(4.75);
expect(series.stats.avg).toBe(4.75);
});
it('average value should be null if all values is null', function() {
......@@ -119,7 +118,7 @@ describe("TimeSeries", function() {
datapoints: [[null,2],[null,3],[null,4],[null,5]]
});
series.getFlotPairs('null');
expect(series.stats.avg).to.be(null);
expect(series.stats.avg).toBe(null);
});
});
......@@ -130,7 +129,7 @@ describe("TimeSeries", function() {
});
it('should set hasMsResolution to false', function() {
expect(series.hasMsResolution).to.be(false);
expect(series.hasMsResolution).toBe(false);
});
});
......@@ -140,7 +139,7 @@ describe("TimeSeries", function() {
});
it('should show millisecond resolution tooltip', function() {
expect(series.hasMsResolution).to.be(true);
expect(series.hasMsResolution).toBe(true);
});
});
......@@ -150,7 +149,7 @@ describe("TimeSeries", function() {
});
it('should not show millisecond resolution tooltip', function() {
expect(series.hasMsResolution).to.be(false);
expect(series.hasMsResolution).toBe(false);
});
});
});
......@@ -165,13 +164,13 @@ describe("TimeSeries", function() {
it('missing datapoint with ms precision', function() {
fakedata.datapoints[0] = [1337, 1234567890000];
series = new TimeSeries(fakedata);
expect(series.isMsResolutionNeeded()).to.be(false);
expect(series.isMsResolutionNeeded()).toBe(false);
});
it('contains datapoint with ms precision', function() {
fakedata.datapoints[0] = [1337, 1236547890001];
series = new TimeSeries(fakedata);
expect(series.isMsResolutionNeeded()).to.be(true);
expect(series.isMsResolutionNeeded()).toBe(true);
});
});
......@@ -188,8 +187,8 @@ describe("TimeSeries", function() {
});
it('should set fill zero, and enable points', function() {
expect(series.lines.fill).to.be(0.001);
expect(series.points.show).to.be(true);
expect(series.lines.fill).toBe(0.001);
expect(series.points.show).toBe(true);
});
});
......@@ -200,8 +199,8 @@ describe("TimeSeries", function() {
});
it('should disable lines, and enable bars', function() {
expect(series.lines.show).to.be(false);
expect(series.bars.show).to.be(true);
expect(series.lines.show).toBe(false);
expect(series.bars.show).toBe(true);
});
});
......@@ -212,8 +211,8 @@ describe("TimeSeries", function() {
});
it('should disable stack, and set lineWidth', function() {
expect(series.stack).to.be(false);
expect(series.lines.lineWidth).to.be(5);
expect(series.stack).toBe(false);
expect(series.lines.lineWidth).toBe(5);
});
});
......@@ -224,9 +223,9 @@ describe("TimeSeries", function() {
});
it('should enable dashes, set dashes lineWidth to 5 and lines lineWidth to 0', function() {
expect(series.dashes.show).to.be(true);
expect(series.dashes.lineWidth).to.be(5);
expect(series.lines.lineWidth).to.be(0);
expect(series.dashes.show).toBe(true);
expect(series.dashes.lineWidth).toBe(5);
expect(series.lines.lineWidth).toBe(0);
});
});
......@@ -237,7 +236,7 @@ describe("TimeSeries", function() {
});
it('should disable line fill and add fillBelowTo', function() {
expect(series.fillBelowTo).to.be('min');
expect(series.fillBelowTo).toBe('min');
});
});
......@@ -248,8 +247,8 @@ describe("TimeSeries", function() {
});
it('should set pointradius, and set steppedLine', function() {
expect(series.points.radius).to.be(5);
expect(series.lines.steps).to.be(true);
expect(series.points.radius).toBe(5);
expect(series.lines.steps).toBe(true);
});
});
......@@ -260,7 +259,7 @@ describe("TimeSeries", function() {
});
it('should match second series', function() {
expect(series.lines.show).to.be(false);
expect(series.lines.show).toBe(false);
});
});
......@@ -271,11 +270,11 @@ describe("TimeSeries", function() {
});
it('should set yaxis', function() {
expect(series.yaxis).to.be(2);
expect(series.yaxis).toBe(2);
});
it('should set zindex', function() {
expect(series.zindex).to.be(2);
expect(series.zindex).toBe(2);
});
});
......@@ -288,11 +287,11 @@ describe("TimeSeries", function() {
});
it('should format non-numeric values as empty string', function() {
expect(series.formatValue(null)).to.be("");
expect(series.formatValue(undefined)).to.be("");
expect(series.formatValue(NaN)).to.be("");
expect(series.formatValue(Infinity)).to.be("");
expect(series.formatValue(-Infinity)).to.be("");
expect(series.formatValue(null)).toBe("");
expect(series.formatValue(undefined)).toBe("");
expect(series.formatValue(NaN)).toBe("");
expect(series.formatValue(Infinity)).toBe("");
expect(series.formatValue(-Infinity)).toBe("");
});
});
......
define([
'./time_series2'
], function(timeSeries) {
'use strict';
// backward compatability hack;
return timeSeries.default;
});
import React from 'react';
import { react2AngularDirective } from 'app/core/utils/react2angular';
export interface IProps {
password: string;
......@@ -33,5 +32,4 @@ export class PasswordStrength extends React.Component<IProps, any> {
}
}
react2AngularDirective('passwordStrength', PasswordStrength, ['password']);
......@@ -15,7 +15,6 @@ define([
'./unsavedChangesSrv',
'./unsaved_changes_modal',
'./timepicker/timepicker',
'./graphiteImportCtrl',
'./impression_store',
'./upload',
'./import/dash_import',
......
......@@ -11,6 +11,8 @@ define([
function (angular, moment, _, $, kbn, dateMath, impressionStore) {
'use strict';
kbn = kbn.default;
var module = angular.module('grafana.services');
module.service('dashboardLoaderSrv', function(backendSrv,
......
define([
'angular',
'lodash',
'app/core/utils/kbn'
],
function (angular, _, kbn) {
'use strict';
var module = angular.module('grafana.controllers');
module.controller('GraphiteImportCtrl', function($scope, datasourceSrv, dashboardSrv, $location) {
$scope.options = {};
$scope.init = function() {
$scope.datasources = [];
_.each(datasourceSrv.getAll(), function(ds) {
if (ds.type === 'graphite') {
$scope.options.sourceName = ds.name;
$scope.datasources.push(ds.name);
}
});
};
$scope.listAll = function() {
datasourceSrv.get($scope.options.sourceName).then(function(datasource) {
$scope.datasource = datasource;
$scope.datasource.listDashboards('').then(function(results) {
$scope.dashboards = results;
}, function(err) {
var message = err.message || err.statusText || 'Error';
$scope.appEvent('alert-error', ['Failed to load dashboard list from graphite', message]);
});
});
};
$scope.import = function(dashName) {
$scope.datasource.loadDashboard(dashName).then(function(results) {
if (!results.data || !results.data.state) {
throw { message: 'no dashboard state received from graphite' };
}
graphiteToGrafanaTranslator(results.data.state, $scope.datasource.name);
}, function(err) {
var message = err.message || err.statusText || 'Error';
$scope.appEvent('alert-error', ['Failed to load dashboard from graphite', message]);
});
};
function graphiteToGrafanaTranslator(state, datasource) {
var graphsPerRow = 2;
var rowHeight = 300;
var rowTemplate;
var currentRow;
var panel;
rowTemplate = {
title: '',
panels: [],
height: rowHeight
};
currentRow = angular.copy(rowTemplate);
var newDashboard = dashboardSrv.create({});
newDashboard.rows = [];
newDashboard.title = state.name;
newDashboard.rows.push(currentRow);
_.each(state.graphs, function(graph, index) {
if (currentRow.panels.length === graphsPerRow) {
currentRow = angular.copy(rowTemplate);
newDashboard.rows.push(currentRow);
}
panel = {
type: 'graph',
span: 12 / graphsPerRow,
title: graph[1].title,
targets: [],
datasource: datasource,
id: index + 1
};
_.each(graph[1].target, function(target) {
panel.targets.push({ target: target });
});
currentRow.panels.push(panel);
});
window.grafanaImportDashboard = newDashboard;
$location.path('/dashboard-import/' + kbn.slugifyForUrl(newDashboard.title));
}
});
});
......@@ -6,6 +6,8 @@ define([
function (angular, _, kbn) {
'use strict';
kbn = kbn.default;
angular
.module('grafana.services')
.service('linkSrv', function(templateSrv, timeSrv) {
......
///<reference path="../../headers/common.d.ts" />
import _ from 'lodash';
import {Variable, assignModelProperties, variableTypes} from './variable';
......
import './templateSrv';
import './editor_ctrl';
import coreModule from 'app/core/core_module';
import {VariableSrv} from './variable_srv';
import {IntervalVariable} from './interval_variable';
import {QueryVariable} from './query_variable';
import {DatasourceVariable} from './datasource_variable';
import {CustomVariable} from './custom_variable';
import {ConstantVariable} from './constant_variable';
import {AdhocVariable} from './adhoc_variable';
import { TemplateSrv } from './template_srv';
import { VariableSrv } from './variable_srv';
import { IntervalVariable } from './interval_variable';
import { QueryVariable } from './query_variable';
import { DatasourceVariable } from './datasource_variable';
import { CustomVariable } from './custom_variable';
import { ConstantVariable } from './constant_variable';
import { AdhocVariable } from './adhoc_variable';
coreModule.service('templateSrv', TemplateSrv);
export {
TemplateSrv,
VariableSrv,
IntervalVariable,
QueryVariable,
......
///<reference path="../../headers/common.d.ts" />
import _ from 'lodash';
import kbn from 'app/core/utils/kbn';
import {Variable, containsVariable, assignModelProperties, variableTypes} from './variable';
......
import {describe, it, expect} from 'test/lib/common';
import {AdhocVariable} from '../adhoc_variable';
describe('AdhocVariable', function() {
......@@ -15,7 +13,7 @@ describe('AdhocVariable', function() {
]
});
var urlValue = variable.getValueForUrl();
expect(urlValue).to.eql(["key1|=|value1", "key2|!=|value2", "key3|=|value3a__gfp__value3b__gfp__value3c"]);
expect(urlValue).toMatchObject(["key1|=|value1", "key2|!=|value2", "key3|=|value3a__gfp__value3b__gfp__value3c"]);
});
});
......@@ -26,17 +24,17 @@ describe('AdhocVariable', function() {
var variable = new AdhocVariable({});
variable.setValueFromUrl(["key1|=|value1", "key2|!=|value2", "key3|=|value3a__gfp__value3b__gfp__value3c"]);
expect(variable.filters[0].key).to.be('key1');
expect(variable.filters[0].operator).to.be('=');
expect(variable.filters[0].value).to.be('value1');
expect(variable.filters[0].key).toBe('key1');
expect(variable.filters[0].operator).toBe('=');
expect(variable.filters[0].value).toBe('value1');
expect(variable.filters[1].key).to.be('key2');
expect(variable.filters[1].operator).to.be('!=');
expect(variable.filters[1].value).to.be('value2');
expect(variable.filters[1].key).toBe('key2');
expect(variable.filters[1].operator).toBe('!=');
expect(variable.filters[1].value).toBe('value2');
expect(variable.filters[2].key).to.be('key3');
expect(variable.filters[2].operator).to.be('=');
expect(variable.filters[2].value).to.be('value3a|value3b|value3c');
expect(variable.filters[2].key).toBe('key3');
expect(variable.filters[2].operator).toBe('=');
expect(variable.filters[2].value).toBe('value3a|value3b|value3c');
});
});
......
import {describe, it, expect} from 'test/lib/common';
import {QueryVariable} from '../query_variable';
describe('QueryVariable', () => {
......@@ -8,14 +6,14 @@ describe('QueryVariable', () => {
it('should set defaults', () => {
var variable = new QueryVariable({}, null, null, null, null);
expect(variable.datasource).to.be(null);
expect(variable.refresh).to.be(0);
expect(variable.sort).to.be(0);
expect(variable.name).to.be('');
expect(variable.hide).to.be(0);
expect(variable.options.length).to.be(0);
expect(variable.multi).to.be(false);
expect(variable.includeAll).to.be(false);
expect(variable.datasource).toBe(null);
expect(variable.refresh).toBe(0);
expect(variable.sort).toBe(0);
expect(variable.name).toBe('');
expect(variable.hide).toBe(0);
expect(variable.options.length).toBe(0);
expect(variable.multi).toBe(false);
expect(variable.includeAll).toBe(false);
});
it('get model should copy changes back to model', () => {
......@@ -26,11 +24,11 @@ describe('QueryVariable', () => {
variable.sort = 50;
var model = variable.getSaveModel();
expect(model.options.length).to.be(1);
expect(model.options[0].text).to.be('test');
expect(model.datasource).to.be('google');
expect(model.regex).to.be('asd');
expect(model.sort).to.be(50);
expect(model.options.length).toBe(1);
expect(model.options[0].text).toBe('test');
expect(model.datasource).toBe('google');
expect(model.regex).toBe('asd');
expect(model.sort).toBe(50);
});
it('if refresh != 0 then remove options in presisted mode', () => {
......@@ -39,7 +37,7 @@ describe('QueryVariable', () => {
variable.refresh = 1;
var model = variable.getSaveModel();
expect(model.options.length).to.be(0);
expect(model.options.length).toBe(0);
});
});
......@@ -67,14 +65,14 @@ describe('QueryVariable', () => {
it('should return in same order', () => {
var i = 0;
expect(result.length).to.be(11);
expect(result[i++].text).to.be('');
expect(result[i++].text).to.be('0');
expect(result[i++].text).to.be('1');
expect(result[i++].text).to.be('3');
expect(result[i++].text).to.be('4');
expect(result[i++].text).to.be('5');
expect(result[i++].text).to.be('6');
expect(result.length).toBe(11);
expect(result[i++].text).toBe('');
expect(result[i++].text).toBe('0');
expect(result[i++].text).toBe('1');
expect(result[i++].text).toBe('3');
expect(result[i++].text).toBe('4');
expect(result[i++].text).toBe('5');
expect(result[i++].text).toBe('6');
});
});
});
......
import {describe, beforeEach, it, expect, angularMocks} from 'test/lib/common';
import '../all';
import {Emitter} from 'app/core/core';
import { TemplateSrv } from '../template_srv';
describe('templateSrv', function() {
var _templateSrv, _variableSrv;
beforeEach(angularMocks.module('grafana.core'));
beforeEach(angularMocks.module('grafana.services'));
beforeEach(angularMocks.module($provide => {
$provide.value('timeSrv', {});
$provide.value('datasourceSrv', {});
}));
beforeEach(angularMocks.inject(function(variableSrv, templateSrv) {
_templateSrv = templateSrv;
_variableSrv = variableSrv;
}));
var _templateSrv;
function initTemplateSrv(variables) {
_variableSrv.init({
templating: {list: variables},
events: new Emitter(),
});
_templateSrv = new TemplateSrv();
_templateSrv.init(variables);
}
describe('init', function() {
......@@ -32,7 +15,7 @@ describe('templateSrv', function() {
it('should initialize template data', function() {
var target = _templateSrv.replace('this.[[test]].filters');
expect(target).to.be('this.oogle.filters');
expect(target).toBe('this.oogle.filters');
});
});
......@@ -43,12 +26,12 @@ describe('templateSrv', function() {
it('should replace $test with scoped value', function() {
var target = _templateSrv.replace('this.$test.filters', {'test': {value: 'mupp', text: 'asd'}});
expect(target).to.be('this.mupp.filters');
expect(target).toBe('this.mupp.filters');
});
it('should replace $test with scoped text', function() {
var target = _templateSrv.replaceWithText('this.$test.filters', {'test': {value: 'mupp', text: 'asd'}});
expect(target).to.be('this.asd.filters');
expect(target).toBe('this.asd.filters');
});
});
......@@ -63,17 +46,17 @@ describe('templateSrv', function() {
it('should return filters if datasourceName match', function() {
var filters = _templateSrv.getAdhocFilters('oogle');
expect(filters).to.eql([1]);
expect(filters).toMatchObject([1]);
});
it('should return empty array if datasourceName does not match', function() {
var filters = _templateSrv.getAdhocFilters('oogleasdasd');
expect(filters).to.eql([]);
expect(filters).toMatchObject([]);
});
it('should return filters when datasourceName match via data source variable', function() {
var filters = _templateSrv.getAdhocFilters('logstash');
expect(filters).to.eql([2]);
expect(filters).toMatchObject([2]);
});
});
......@@ -84,17 +67,17 @@ describe('templateSrv', function() {
it('should replace $test with globbed value', function() {
var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
expect(target).to.be('this.{value1,value2}.filters');
expect(target).toBe('this.{value1,value2}.filters');
});
it('should replace $test with piped value', function() {
var target = _templateSrv.replace('this=$test', {}, 'pipe');
expect(target).to.be('this=value1|value2');
expect(target).toBe('this=value1|value2');
});
it('should replace $test with piped value', function() {
var target = _templateSrv.replace('this=$test', {}, 'pipe');
expect(target).to.be('this=value1|value2');
expect(target).toBe('this=value1|value2');
});
});
......@@ -112,7 +95,7 @@ describe('templateSrv', function() {
it('should replace $test with formatted all value', function() {
var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
expect(target).to.be('this.{value1,value2}.filters');
expect(target).toBe('this.{value1,value2}.filters');
});
});
......@@ -131,12 +114,12 @@ describe('templateSrv', function() {
it('should replace $test with formatted all value', function() {
var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
expect(target).to.be('this.*.filters');
expect(target).toBe('this.*.filters');
});
it('should not escape custom all value', function() {
var target = _templateSrv.replace('this.$test', {}, 'regex');
expect(target).to.be('this.*');
expect(target).toBe('this.*');
});
});
......@@ -144,49 +127,49 @@ describe('templateSrv', function() {
it('should properly escape $test with lucene escape sequences', function() {
initTemplateSrv([{type: 'query', name: 'test', current: {value: 'value/4' }}]);
var target = _templateSrv.replace('this:$test', {}, 'lucene');
expect(target).to.be("this:value\\\/4");
expect(target).toBe("this:value\\\/4");
});
});
describe('format variable to string values', function() {
it('single value should return value', function() {
var result = _templateSrv.formatValue('test');
expect(result).to.be('test');
expect(result).toBe('test');
});
it('multi value and glob format should render glob string', function() {
var result = _templateSrv.formatValue(['test','test2'], 'glob');
expect(result).to.be('{test,test2}');
expect(result).toBe('{test,test2}');
});
it('multi value and lucene should render as lucene expr', function() {
var result = _templateSrv.formatValue(['test','test2'], 'lucene');
expect(result).to.be('("test" OR "test2")');
expect(result).toBe('("test" OR "test2")');
});
it('multi value and regex format should render regex string', function() {
var result = _templateSrv.formatValue(['test.','test2'], 'regex');
expect(result).to.be('(test\\.|test2)');
expect(result).toBe('(test\\.|test2)');
});
it('multi value and pipe should render pipe string', function() {
var result = _templateSrv.formatValue(['test','test2'], 'pipe');
expect(result).to.be('test|test2');
expect(result).toBe('test|test2');
});
it('multi value and distributed should render distributed string', function() {
var result = _templateSrv.formatValue(['test','test2'], 'distributed', { name: 'build' });
expect(result).to.be('test,build=test2');
expect(result).toBe('test,build=test2');
});
it('multi value and distributed should render when not string', function() {
var result = _templateSrv.formatValue(['test'], 'distributed', { name: 'build' });
expect(result).to.be('test');
expect(result).toBe('test');
});
it('slash should be properly escaped in regex format', function() {
var result = _templateSrv.formatValue('Gi3/14', 'regex');
expect(result).to.be('Gi3\\/14');
expect(result).toBe('Gi3\\/14');
});
});
......@@ -198,7 +181,7 @@ describe('templateSrv', function() {
it('should return true if exists', function() {
var result = _templateSrv.variableExists('$test');
expect(result).to.be(true);
expect(result).toBe(true);
});
});
......@@ -209,17 +192,17 @@ describe('templateSrv', function() {
it('should insert html', function() {
var result = _templateSrv.highlightVariablesAsHtml('$test');
expect(result).to.be('<span class="template-variable">$test</span>');
expect(result).toBe('<span class="template-variable">$test</span>');
});
it('should insert html anywhere in string', function() {
var result = _templateSrv.highlightVariablesAsHtml('this $test ok');
expect(result).to.be('this <span class="template-variable">$test</span> ok');
expect(result).toBe('this <span class="template-variable">$test</span> ok');
});
it('should ignore if variables does not exist', function() {
var result = _templateSrv.highlightVariablesAsHtml('this $google ok');
expect(result).to.be('this $google ok');
expect(result).toBe('this $google ok');
});
});
......@@ -230,19 +213,28 @@ describe('templateSrv', function() {
it('should set current value and update template data', function() {
var target = _templateSrv.replace('this.[[test]].filters');
expect(target).to.be('this.muuuu.filters');
expect(target).toBe('this.muuuu.filters');
});
});
describe('fillVariableValuesForUrl with multi value', function() {
beforeEach(function() {
initTemplateSrv([{type: 'query', name: 'test', current: { value: ['val1', 'val2'] }}]);
initTemplateSrv([
{
type: 'query',
name: 'test',
current: { value: ['val1', 'val2'] },
getValueForUrl: function() {
return this.current.value;
}
}
]);
});
it('should set multiple url params', function() {
var params = {};
_templateSrv.fillVariableValuesForUrl(params);
expect(params['var-test']).to.eql(['val1', 'val2']);
expect(params['var-test']).toMatchObject(['val1', 'val2']);
});
});
......@@ -254,7 +246,7 @@ describe('templateSrv', function() {
it('should set scoped value as url params', function() {
var params = {};
_templateSrv.fillVariableValuesForUrl(params, {'test': {value: 'val1'}});
expect(params['var-test']).to.eql('val1');
expect(params['var-test']).toBe('val1');
});
});
......@@ -270,7 +262,7 @@ describe('templateSrv', function() {
it('should replace with text except for grafanaVariables', function() {
var target = _templateSrv.replaceWithText('Server: $server, period: $period');
expect(target).to.be('Server: All, period: 13m');
expect(target).toBe('Server: All, period: 13m');
});
});
......@@ -281,7 +273,7 @@ describe('templateSrv', function() {
it('should replace $__interval_ms with interval milliseconds', function() {
var target = _templateSrv.replace('10 * $__interval_ms', {"__interval_ms": {text: "100", value: "100"}});
expect(target).to.be('10 * 100');
expect(target).toBe('10 * 100');
});
});
......
define([
'angular',
'lodash',
'app/core/utils/kbn',
],
function (angular, _, kbn) {
'use strict';
var module = angular.module('grafana.services');
module.service('templateSrv', function() {
var self = this;
this._regex = /\$(\w+)|\[\[([\s\S]+?)\]\]/g;
this._index = {};
this._texts = {};
this._grafanaVariables = {};
// default built ins
this._builtIns = {};
this._builtIns['__interval'] = {text: '1s', value: '1s'};
this._builtIns['__interval_ms'] = {text: '100', value: '100'};
this.init = function(variables) {
import kbn from 'app/core/utils/kbn';
import _ from 'lodash';
function luceneEscape(value) {
return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, "\\$1");
}
export class TemplateSrv {
variables: any[];
private regex = /\$(\w+)|\[\[([\s\S]+?)\]\]/g;
private index = {};
private grafanaVariables = {};
private builtIns = {};
private filters = {};
constructor() {
this.builtIns['__interval'] = {text: '1s', value: '1s'};
this.builtIns['__interval_ms'] = {text: '100', value: '100'};
}
init(variables) {
this.variables = variables;
this.updateTemplateData();
};
}
this.updateTemplateData = function() {
this._index = {};
this._filters = {};
updateTemplateData() {
this.index = {};
this.filters = {};
for (var i = 0; i < this.variables.length; i++) {
var variable = this.variables[i];
......@@ -37,15 +35,15 @@ function (angular, _, kbn) {
continue;
}
this._index[variable.name] = variable;
this.index[variable.name] = variable;
}
}
};
this.variableInitialized = function(variable) {
this._index[variable.name] = variable;
};
variableInitialized(variable) {
this.index[variable.name] = variable;
}
this.getAdhocFilters = function(datasourceName) {
getAdhocFilters(datasourceName) {
var filters = [];
for (var i = 0; i < this.variables.length; i++) {
......@@ -66,13 +64,9 @@ function (angular, _, kbn) {
}
return filters;
};
function luceneEscape(value) {
return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, "\\$1");
}
this.luceneFormat = function(value) {
luceneFormat(value) {
if (typeof value === 'string') {
return luceneEscape(value);
}
......@@ -80,9 +74,9 @@ function (angular, _, kbn) {
return '\"' + luceneEscape(val) + '\"';
});
return '(' + quotedValues.join(' OR ') + ')';
};
}
this.formatValue = function(value, format, variable) {
formatValue(value, format, variable) {
// for some scopedVars there is no variable
variable = variable || {};
......@@ -90,7 +84,7 @@ function (angular, _, kbn) {
return format(value, variable, this.formatValue);
}
switch(format) {
switch (format) {
case "regex": {
if (typeof value === 'string') {
return kbn.regexEscape(value);
......@@ -100,7 +94,7 @@ function (angular, _, kbn) {
return '(' + escapedValues.join('|') + ')';
}
case "lucene": {
return this.luceneFormat(value, format, variable);
return this.luceneFormat(value);
}
case "pipe": {
if (typeof value === 'string') {
......@@ -121,40 +115,40 @@ function (angular, _, kbn) {
return value;
}
}
};
}
this.setGrafanaVariable = function (name, value) {
this._grafanaVariables[name] = value;
};
setGrafanaVariable(name, value) {
this.grafanaVariables[name] = value;
}
this.getVariableName = function(expression) {
this._regex.lastIndex = 0;
var match = this._regex.exec(expression);
getVariableName(expression) {
this.regex.lastIndex = 0;
var match = this.regex.exec(expression);
if (!match) {
return null;
}
return match[1] || match[2];
};
}
this.variableExists = function(expression) {
variableExists(expression) {
var name = this.getVariableName(expression);
return name && (self._index[name] !== void 0);
};
return name && (this.index[name] !== void 0);
}
this.highlightVariablesAsHtml = function(str) {
highlightVariablesAsHtml(str) {
if (!str || !_.isString(str)) { return str; }
str = _.escape(str);
this._regex.lastIndex = 0;
return str.replace(this._regex, function(match, g1, g2) {
if (self._index[g1 || g2] || self._builtIns[g1 || g2]) {
this.regex.lastIndex = 0;
return str.replace(this.regex, (match, g1, g2) => {
if (this.index[g1 || g2] || this.builtIns[g1 || g2]) {
return '<span class="template-variable">' + match + '</span>';
}
return match;
});
};
}
this.getAllValue = function(variable) {
getAllValue(variable) {
if (variable.allValue) {
return variable.allValue;
}
......@@ -163,21 +157,21 @@ function (angular, _, kbn) {
values.push(variable.options[i].value);
}
return values;
};
}
this.replace = function(target, scopedVars, format) {
replace(target, scopedVars?, format?) {
if (!target) { return target; }
var variable, systemValue, value;
this._regex.lastIndex = 0;
this.regex.lastIndex = 0;
return target.replace(this._regex, function(match, g1, g2) {
variable = self._index[g1 || g2];
return target.replace(this.regex, (match, g1, g2) => {
variable = this.index[g1 || g2];
if (scopedVars) {
value = scopedVars[g1 || g2];
if (value) {
return self.formatValue(value.value, format, variable);
return this.formatValue(value.value, format, variable);
}
}
......@@ -185,49 +179,49 @@ function (angular, _, kbn) {
return match;
}
systemValue = self._grafanaVariables[variable.current.value];
systemValue = this.grafanaVariables[variable.current.value];
if (systemValue) {
return self.formatValue(systemValue, format, variable);
return this.formatValue(systemValue, format, variable);
}
value = variable.current.value;
if (self.isAllValue(value)) {
value = self.getAllValue(variable);
if (this.isAllValue(value)) {
value = this.getAllValue(variable);
// skip formating of custom all values
if (variable.allValue) {
return value;
}
}
var res = self.formatValue(value, format, variable);
var res = this.formatValue(value, format, variable);
return res;
});
};
}
this.isAllValue = function(value) {
isAllValue(value) {
return value === '$__all' || Array.isArray(value) && value[0] === '$__all';
};
}
this.replaceWithText = function(target, scopedVars) {
replaceWithText(target, scopedVars) {
if (!target) { return target; }
var variable;
this._regex.lastIndex = 0;
this.regex.lastIndex = 0;
return target.replace(this._regex, function(match, g1, g2) {
return target.replace(this.regex, (match, g1, g2) => {
if (scopedVars) {
var option = scopedVars[g1 || g2];
if (option) { return option.text; }
}
variable = self._index[g1 || g2];
variable = this.index[g1 || g2];
if (!variable) { return match; }
return self._grafanaVariables[variable.current.value] || variable.current.text;
return this.grafanaVariables[variable.current.value] || variable.current.text;
});
};
}
this.fillVariableValuesForUrl = function(params, scopedVars) {
fillVariableValuesForUrl(params, scopedVars) {
_.each(this.variables, function(variable) {
if (scopedVars && scopedVars[variable.name] !== void 0) {
params['var-' + variable.name] = scopedVars[variable.name].value;
......@@ -235,9 +229,9 @@ function (angular, _, kbn) {
params['var-' + variable.name] = variable.getValueForUrl();
}
});
};
}
this.distributeVariable = function(value, variable) {
distributeVariable(value, variable) {
value = _.map(value, function(val, index) {
if (index !== 0) {
return variable + "=" + val;
......@@ -246,8 +240,5 @@ function (angular, _, kbn) {
}
});
return value.join(',');
};
});
});
}
}
///<reference path="../../headers/common.d.ts" />
import kbn from 'app/core/utils/kbn';
import {assignModelProperties} from 'app/core/core';
import {assignModelProperties} from 'app/core/utils/model_utils';
export interface Variable {
setValue(option);
......
......@@ -9,6 +9,8 @@ define([
function (angular, _, moment, dateMath, kbn, templatingVariable) {
'use strict';
kbn = kbn.default;
/** @ngInject */
function CloudWatchDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv) {
this.type = 'cloudwatch';
......
......@@ -7,6 +7,8 @@ define([
function (angular, _, $, gfunc) {
'use strict';
gfunc = gfunc.default;
angular
.module('grafana.directives')
.directive('graphiteAddFunc', function($compile) {
......
declare var test: any;
export default test;
import {describe, it, expect} from 'test/lib/common';
import gfunc from '../gfunc';
describe('when creating func instance from func names', function() {
it('should return func instance', function() {
var func = gfunc.createFuncInstance('sumSeries');
expect(func).to.be.ok();
expect(func.def.name).to.equal('sumSeries');
expect(func.def.params.length).to.equal(5);
expect(func.def.defaultParams.length).to.equal(1);
expect(func).toBeTruthy();
expect(func.def.name).toEqual('sumSeries');
expect(func.def.params.length).toEqual(5);
expect(func.def.defaultParams.length).toEqual(1);
});
it('should return func instance with shortName', function() {
var func = gfunc.createFuncInstance('sum');
expect(func).to.be.ok();
expect(func).toBeTruthy();
});
it('should return func instance from funcDef', function() {
var func = gfunc.createFuncInstance('sum');
var func2 = gfunc.createFuncInstance(func.def);
expect(func2).to.be.ok();
expect(func2).toBeTruthy();
});
it('func instance should have text representation', function() {
......@@ -27,7 +25,7 @@ describe('when creating func instance from func names', function() {
func.params[0] = 5;
func.params[1] = 'avg';
func.updateText();
expect(func.text).to.equal("groupByNode(5, avg)");
expect(func.text).toEqual("groupByNode(5, avg)");
});
});
......@@ -35,51 +33,51 @@ describe('when rendering func instance', function() {
it('should handle single metric param', function() {
var func = gfunc.createFuncInstance('sumSeries');
expect(func.render('hello.metric')).to.equal("sumSeries(hello.metric)");
expect(func.render('hello.metric')).toEqual("sumSeries(hello.metric)");
});
it('should include default params if options enable it', function() {
var func = gfunc.createFuncInstance('scaleToSeconds', { withDefaultParams: true });
expect(func.render('hello')).to.equal("scaleToSeconds(hello, 1)");
expect(func.render('hello')).toEqual("scaleToSeconds(hello, 1)");
});
it('should handle int or interval params with number', function() {
var func = gfunc.createFuncInstance('movingMedian');
func.params[0] = '5';
expect(func.render('hello')).to.equal("movingMedian(hello, 5)");
expect(func.render('hello')).toEqual("movingMedian(hello, 5)");
});
it('should handle int or interval params with interval string', function() {
var func = gfunc.createFuncInstance('movingMedian');
func.params[0] = '5min';
expect(func.render('hello')).to.equal("movingMedian(hello, '5min')");
expect(func.render('hello')).toEqual("movingMedian(hello, '5min')");
});
it('should handle metric param and int param and string param', function() {
var func = gfunc.createFuncInstance('groupByNode');
func.params[0] = 5;
func.params[1] = 'avg';
expect(func.render('hello.metric')).to.equal("groupByNode(hello.metric, 5, 'avg')");
expect(func.render('hello.metric')).toEqual("groupByNode(hello.metric, 5, 'avg')");
});
it('should handle function with no metric param', function() {
var func = gfunc.createFuncInstance('randomWalk');
func.params[0] = 'test';
expect(func.render(undefined)).to.equal("randomWalk('test')");
expect(func.render(undefined)).toEqual("randomWalk('test')");
});
it('should handle function multiple series params', function() {
var func = gfunc.createFuncInstance('asPercent');
func.params[0] = '#B';
expect(func.render('#A')).to.equal("asPercent(#A, #B)");
expect(func.render('#A')).toEqual("asPercent(#A, #B)");
});
});
describe('when requesting function categories', function() {
it('should return function categories', function() {
var catIndex = gfunc.getCategories();
expect(catIndex.Special.length).to.be.greaterThan(8);
var catIndex = gfunc.getCategories('1.0');
expect(catIndex.Special.length).toBeGreaterThan(8);
});
});
......@@ -87,14 +85,14 @@ describe('when updating func param', function() {
it('should update param value and update text representation', function() {
var func = gfunc.createFuncInstance('summarize', { withDefaultParams: true });
func.updateParam('1h', 0);
expect(func.params[0]).to.be('1h');
expect(func.text).to.be('summarize(1h, sum, false)');
expect(func.params[0]).toBe('1h');
expect(func.text).toBe('summarize(1h, sum, false)');
});
it('should parse numbers as float', function() {
var func = gfunc.createFuncInstance('scale');
func.updateParam('0.001', 0);
expect(func.params[0]).to.be('0.001');
expect(func.params[0]).toBe('0.001');
});
});
......@@ -102,24 +100,24 @@ describe('when updating func param with optional second parameter', function() {
it('should update value and text', function() {
var func = gfunc.createFuncInstance('aliasByNode');
func.updateParam('1', 0);
expect(func.params[0]).to.be('1');
expect(func.params[0]).toBe('1');
});
it('should slit text and put value in second param', function() {
var func = gfunc.createFuncInstance('aliasByNode');
func.updateParam('4,-5', 0);
expect(func.params[0]).to.be('4');
expect(func.params[1]).to.be('-5');
expect(func.text).to.be('aliasByNode(4, -5)');
expect(func.params[0]).toBe('4');
expect(func.params[1]).toBe('-5');
expect(func.text).toBe('aliasByNode(4, -5)');
});
it('should remove second param when empty string is set', function() {
var func = gfunc.createFuncInstance('aliasByNode');
func.updateParam('4,-5', 0);
func.updateParam('', 1);
expect(func.params[0]).to.be('4');
expect(func.params[1]).to.be(undefined);
expect(func.text).to.be('aliasByNode(4)');
expect(func.params[0]).toBe('4');
expect(func.params[1]).toBe(undefined);
expect(func.text).toBe('aliasByNode(4)');
});
});
import {describe, it, expect} from 'test/lib/common';
import {Lexer} from '../lexer';
describe('when lexing graphite expression', function() {
......@@ -7,120 +5,120 @@ describe('when lexing graphite expression', function() {
it('should tokenize metric expression', function() {
var lexer = new Lexer('metric.test.*.asd.count');
var tokens = lexer.tokenize();
expect(tokens[0].value).to.be('metric');
expect(tokens[1].value).to.be('.');
expect(tokens[2].type).to.be('identifier');
expect(tokens[4].type).to.be('identifier');
expect(tokens[4].pos).to.be(13);
expect(tokens[0].value).toBe('metric');
expect(tokens[1].value).toBe('.');
expect(tokens[2].type).toBe('identifier');
expect(tokens[4].type).toBe('identifier');
expect(tokens[4].pos).toBe(13);
});
it('should tokenize metric expression with dash', function() {
var lexer = new Lexer('metric.test.se1-server-*.asd.count');
var tokens = lexer.tokenize();
expect(tokens[4].type).to.be('identifier');
expect(tokens[4].value).to.be('se1-server-*');
expect(tokens[4].type).toBe('identifier');
expect(tokens[4].value).toBe('se1-server-*');
});
it('should tokenize metric expression with dash2', function() {
var lexer = new Lexer('net.192-168-1-1.192-168-1-9.ping_value.*');
var tokens = lexer.tokenize();
expect(tokens[0].value).to.be('net');
expect(tokens[2].value).to.be('192-168-1-1');
expect(tokens[0].value).toBe('net');
expect(tokens[2].value).toBe('192-168-1-1');
});
it('should tokenize metric expression with equal sign', function() {
var lexer = new Lexer('apps=test');
var tokens = lexer.tokenize();
expect(tokens[0].value).to.be('apps=test');
expect(tokens[0].value).toBe('apps=test');
});
it('simple function2', function() {
var lexer = new Lexer('offset(test.metric, -100)');
var tokens = lexer.tokenize();
expect(tokens[2].type).to.be('identifier');
expect(tokens[4].type).to.be('identifier');
expect(tokens[6].type).to.be('number');
expect(tokens[2].type).toBe('identifier');
expect(tokens[4].type).toBe('identifier');
expect(tokens[6].type).toBe('number');
});
it('should tokenize metric expression with curly braces', function() {
var lexer = new Lexer('metric.se1-{first, second}.count');
var tokens = lexer.tokenize();
expect(tokens.length).to.be(10);
expect(tokens[3].type).to.be('{');
expect(tokens[4].value).to.be('first');
expect(tokens[5].value).to.be(',');
expect(tokens[6].value).to.be('second');
expect(tokens.length).toBe(10);
expect(tokens[3].type).toBe('{');
expect(tokens[4].value).toBe('first');
expect(tokens[5].value).toBe(',');
expect(tokens[6].value).toBe('second');
});
it('should tokenize metric expression with number segments', function() {
var lexer = new Lexer("metric.10.12_10.test");
var tokens = lexer.tokenize();
expect(tokens[0].type).to.be('identifier');
expect(tokens[2].type).to.be('identifier');
expect(tokens[2].value).to.be('10');
expect(tokens[4].value).to.be('12_10');
expect(tokens[4].type).to.be('identifier');
expect(tokens[0].type).toBe('identifier');
expect(tokens[2].type).toBe('identifier');
expect(tokens[2].value).toBe('10');
expect(tokens[4].value).toBe('12_10');
expect(tokens[4].type).toBe('identifier');
});
it('should tokenize metric expression with segment that start with number', function() {
var lexer = new Lexer("metric.001-server");
var tokens = lexer.tokenize();
expect(tokens[0].type).to.be('identifier');
expect(tokens[2].type).to.be('identifier');
expect(tokens.length).to.be(3);
expect(tokens[0].type).toBe('identifier');
expect(tokens[2].type).toBe('identifier');
expect(tokens.length).toBe(3);
});
it('should tokenize func call with numbered metric and number arg', function() {
var lexer = new Lexer("scale(metric.10, 15)");
var tokens = lexer.tokenize();
expect(tokens[0].type).to.be('identifier');
expect(tokens[2].type).to.be('identifier');
expect(tokens[2].value).to.be('metric');
expect(tokens[4].value).to.be('10');
expect(tokens[4].type).to.be('number');
expect(tokens[6].type).to.be('number');
expect(tokens[0].type).toBe('identifier');
expect(tokens[2].type).toBe('identifier');
expect(tokens[2].value).toBe('metric');
expect(tokens[4].value).toBe('10');
expect(tokens[4].type).toBe('number');
expect(tokens[6].type).toBe('number');
});
it('should tokenize metric with template parameter', function() {
var lexer = new Lexer("metric.[[server]].test");
var tokens = lexer.tokenize();
expect(tokens[2].type).to.be('identifier');
expect(tokens[2].value).to.be('[[server]]');
expect(tokens[4].type).to.be('identifier');
expect(tokens[2].type).toBe('identifier');
expect(tokens[2].value).toBe('[[server]]');
expect(tokens[4].type).toBe('identifier');
});
it('should tokenize metric with question mark', function() {
var lexer = new Lexer("metric.server_??.test");
var tokens = lexer.tokenize();
expect(tokens[2].type).to.be('identifier');
expect(tokens[2].value).to.be('server_??');
expect(tokens[4].type).to.be('identifier');
expect(tokens[2].type).toBe('identifier');
expect(tokens[2].value).toBe('server_??');
expect(tokens[4].type).toBe('identifier');
});
it('should handle error with unterminated string', function() {
var lexer = new Lexer("alias(metric, 'asd)");
var tokens = lexer.tokenize();
expect(tokens[0].value).to.be('alias');
expect(tokens[1].value).to.be('(');
expect(tokens[2].value).to.be('metric');
expect(tokens[3].value).to.be(',');
expect(tokens[4].type).to.be('string');
expect(tokens[4].isUnclosed).to.be(true);
expect(tokens[4].pos).to.be(20);
expect(tokens[0].value).toBe('alias');
expect(tokens[1].value).toBe('(');
expect(tokens[2].value).toBe('metric');
expect(tokens[3].value).toBe(',');
expect(tokens[4].type).toBe('string');
expect(tokens[4].isUnclosed).toBe(true);
expect(tokens[4].pos).toBe(20);
});
it('should handle float parameters', function() {
var lexer = new Lexer("alias(metric, 0.002)");
var tokens = lexer.tokenize();
expect(tokens[4].type).to.be('number');
expect(tokens[4].value).to.be('0.002');
expect(tokens[4].type).toBe('number');
expect(tokens[4].value).toBe('0.002');
});
it('should handle bool parameters', function() {
var lexer = new Lexer("alias(metric, true, false)");
var tokens = lexer.tokenize();
expect(tokens[4].type).to.be('bool');
expect(tokens[4].value).to.be('true');
expect(tokens[6].type).to.be('bool');
expect(tokens[4].type).toBe('bool');
expect(tokens[4].value).toBe('true');
expect(tokens[6].type).toBe('bool');
});
});
///<reference path="../../../headers/common.d.ts" />
import {MetricsPanelCtrl} from 'app/plugins/sdk';
import _ from 'lodash';
import kbn from 'app/core/utils/kbn';
import TimeSeries from 'app/core/time_series';
import TimeSeries from 'app/core/time_series2';
import {axesEditor} from './axes_editor';
import {heatmapDisplayEditor} from './display_editor';
import rendering from './rendering';
import {convertToHeatMap, convertToCards, elasticHistogramToHeatmap, calculateBucketSize, getMinLog} from './heatmap_data_converter';
import {convertToHeatMap, convertToCards, elasticHistogramToHeatmap, calculateBucketSize } from './heatmap_data_converter';
let X_BUCKET_NUMBER_DEFAULT = 30;
let Y_BUCKET_NUMBER_DEFAULT = 10;
......@@ -250,7 +248,6 @@ export class HeatmapCtrl extends MetricsPanelCtrl {
});
series.flotpairs = series.getFlotPairs(this.panel.nullPointMode);
series.minLog = getMinLog(series);
let datapoints = seriesData.datapoints || [];
if (datapoints && datapoints.length > 0) {
......@@ -266,7 +263,7 @@ export class HeatmapCtrl extends MetricsPanelCtrl {
parseSeries(series) {
let min = _.min(_.map(series, s => s.stats.min));
let minLog = _.min(_.map(series, s => s.minLog));
let minLog = _.min(_.map(series, s => s.stats.logmin));
let max = _.max(_.map(series, s => s.stats.max));
return {
......
///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash';
let VALUE_INDEX = 0;
......@@ -320,12 +318,6 @@ function convertToLogScaleValueBuckets(xBucket, yBucketSplitFactor, logBase) {
return buckets;
}
// Get minimum non zero value.
function getMinLog(series) {
let values = _.compact(_.map(series.datapoints, p => p[0]));
return _.min(values);
}
/**
* Logarithm for custom base
* @param value
......@@ -432,7 +424,6 @@ export {
elasticHistogramToHeatmap,
convertToCards,
mergeZeroBuckets,
getMinLog,
getValueBucketBound,
isHeatmapDataEqual,
calculateBucketSize
......
///<reference path="../../../../headers/common.d.ts" />
import _ from 'lodash';
import { describe, beforeEach, it, expect } from '../../../../../test/lib/common';
import TimeSeries from 'app/core/time_series2';
......@@ -45,23 +43,23 @@ describe('isHeatmapDataEqual', () => {
let emptyValues = _.cloneDeep(ctx.heatmapA);
emptyValues['1422774000000'].buckets['1'].values = [];
expect(isHeatmapDataEqual(ctx.heatmapA, ctx.heatmapB)).to.be(true);
expect(isHeatmapDataEqual(ctx.heatmapB, ctx.heatmapA)).to.be(true);
expect(isHeatmapDataEqual(ctx.heatmapA, ctx.heatmapB)).toBe(true);
expect(isHeatmapDataEqual(ctx.heatmapB, ctx.heatmapA)).toBe(true);
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapC)).to.be(true);
expect(isHeatmapDataEqual(heatmapC, ctx.heatmapA)).to.be(true);
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapC)).toBe(true);
expect(isHeatmapDataEqual(heatmapC, ctx.heatmapA)).toBe(true);
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapD)).to.be(false);
expect(isHeatmapDataEqual(heatmapD, ctx.heatmapA)).to.be(false);
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapD)).toBe(false);
expect(isHeatmapDataEqual(heatmapD, ctx.heatmapA)).toBe(false);
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapE)).to.be(false);
expect(isHeatmapDataEqual(heatmapE, ctx.heatmapA)).to.be(false);
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapE)).toBe(false);
expect(isHeatmapDataEqual(heatmapE, ctx.heatmapA)).toBe(false);
expect(isHeatmapDataEqual(empty, ctx.heatmapA)).to.be(false);
expect(isHeatmapDataEqual(ctx.heatmapA, empty)).to.be(false);
expect(isHeatmapDataEqual(empty, ctx.heatmapA)).toBe(false);
expect(isHeatmapDataEqual(ctx.heatmapA, empty)).toBe(false);
expect(isHeatmapDataEqual(emptyValues, ctx.heatmapA)).to.be(false);
expect(isHeatmapDataEqual(ctx.heatmapA, emptyValues)).to.be(false);
expect(isHeatmapDataEqual(emptyValues, ctx.heatmapA)).toBe(false);
expect(isHeatmapDataEqual(ctx.heatmapA, emptyValues)).toBe(false);
});
});
......@@ -87,7 +85,7 @@ describe('calculateBucketSize', () => {
it('should properly calculate bucket size', () => {
_.each(ctx.bounds_set, (b) => {
let bucketSize = calculateBucketSize(b.bounds, ctx.logBase);
expect(bucketSize).to.be(b.size);
expect(bucketSize).toBe(b.size);
});
});
});
......@@ -108,7 +106,7 @@ describe('calculateBucketSize', () => {
it('should properly calculate bucket size', () => {
_.each(ctx.bounds_set, (b) => {
let bucketSize = calculateBucketSize(b.bounds, ctx.logBase);
expect(isEqual(bucketSize, b.size)).to.be(true);
expect(isEqual(bucketSize, b.size)).toBe(true);
});
});
});
......@@ -162,7 +160,7 @@ describe('HeatmapDataConverter', () => {
};
let heatmap = convertToHeatMap(ctx.series, ctx.yBucketSize, ctx.xBucketSize, ctx.logBase);
expect(isHeatmapDataEqual(heatmap, expectedHeatmap)).to.be(true);
expect(isHeatmapDataEqual(heatmap, expectedHeatmap)).toBe(true);
});
});
......@@ -190,7 +188,7 @@ describe('HeatmapDataConverter', () => {
};
let heatmap = convertToHeatMap(ctx.series, ctx.yBucketSize, ctx.xBucketSize, ctx.logBase);
expect(isHeatmapDataEqual(heatmap, expectedHeatmap)).to.be(true);
expect(isHeatmapDataEqual(heatmap, expectedHeatmap)).toBe(true);
});
});
});
......@@ -240,7 +238,7 @@ describe('ES Histogram converter', () => {
};
let heatmap = elasticHistogramToHeatmap(ctx.series);
expect(heatmap).to.eql(expectedHeatmap);
expect(heatmap).toMatchObject(expectedHeatmap);
});
});
});
......@@ -273,13 +271,13 @@ describe('convertToCards', () => {
{x: 1422774060000, y: 2, count: 2, values: [2, 3], yBounds: {}}
];
let res = convertToCards(buckets);
expect(res.cards).to.eql(expectedCards);
expect(res.cards).toMatchObject(expectedCards);
});
it('should build proper cards stats', () => {
let expectedStats = {min: 1, max: 2};
let res = convertToCards(buckets);
expect(res.cardStats).to.eql(expectedStats);
expect(res.cardStats).toMatchObject(expectedStats);
});
});
......
///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash';
import moment from 'moment';
import kbn from 'app/core/utils/kbn';
......
import {describe, it, expect} from 'test/lib/common';
import _ from 'lodash';
import TableModel from 'app/core/table_model';
import {TableRenderer} from '../renderer';
......@@ -92,84 +90,84 @@ describe('when rendering table', () => {
it('time column should be formated', () => {
var html = renderer.renderCell(0, 0, 1388556366666);
expect(html).to.be('<td>2014-01-01T06:06:06Z</td>');
expect(html).toBe('<td>2014-01-01T06:06:06Z</td>');
});
it('undefined time column should be rendered as -', () => {
var html = renderer.renderCell(0, 0, undefined);
expect(html).to.be('<td>-</td>');
expect(html).toBe('<td>-</td>');
});
it('null time column should be rendered as -', () => {
var html = renderer.renderCell(0, 0, null);
expect(html).to.be('<td>-</td>');
expect(html).toBe('<td>-</td>');
});
it('number column with unit specified should ignore style unit', () => {
var html = renderer.renderCell(5, 0, 1230);
expect(html).to.be('<td>1.23 kbps</td>');
expect(html).toBe('<td>1.23 kbps</td>');
});
it('number column should be formated', () => {
var html = renderer.renderCell(1, 0, 1230);
expect(html).to.be('<td>1.230 s</td>');
expect(html).toBe('<td>1.230 s</td>');
});
it('number style should ignore string values', () => {
var html = renderer.renderCell(1, 0, 'asd');
expect(html).to.be('<td>asd</td>');
expect(html).toBe('<td>asd</td>');
});
it('colored cell should have style', () => {
var html = renderer.renderCell(2, 0, 40);
expect(html).to.be('<td style="color:green">40.0</td>');
expect(html).toBe('<td style="color:green">40.0</td>');
});
it('colored cell should have style', () => {
var html = renderer.renderCell(2, 0, 55);
expect(html).to.be('<td style="color:orange">55.0</td>');
expect(html).toBe('<td style="color:orange">55.0</td>');
});
it('colored cell should have style', () => {
var html = renderer.renderCell(2, 0, 85);
expect(html).to.be('<td style="color:red">85.0</td>');
expect(html).toBe('<td style="color:red">85.0</td>');
});
it('unformated undefined should be rendered as string', () => {
var html = renderer.renderCell(3, 0, 'value');
expect(html).to.be('<td>value</td>');
expect(html).toBe('<td>value</td>');
});
it('string style with escape html should return escaped html', () => {
var html = renderer.renderCell(4, 0, "&breaking <br /> the <br /> row");
expect(html).to.be('<td>&amp;breaking &lt;br /&gt; the &lt;br /&gt; row</td>');
expect(html).toBe('<td>&amp;breaking &lt;br /&gt; the &lt;br /&gt; row</td>');
});
it('undefined formater should return escaped html', () => {
var html = renderer.renderCell(3, 0, "&breaking <br /> the <br /> row");
expect(html).to.be('<td>&amp;breaking &lt;br /&gt; the &lt;br /&gt; row</td>');
expect(html).toBe('<td>&amp;breaking &lt;br /&gt; the &lt;br /&gt; row</td>');
});
it('undefined value should render as -', () => {
var html = renderer.renderCell(3, 0, undefined);
expect(html).to.be('<td></td>');
expect(html).toBe('<td></td>');
});
it('sanitized value should render as', () => {
var html = renderer.renderCell(6, 0, 'text <a href="http://google.com">link</a>');
expect(html).to.be('<td>sanitized</td>');
expect(html).toBe('<td>sanitized</td>');
});
it('Time column title should be Timestamp', () => {
expect(table.columns[0].title).to.be('Timestamp');
expect(table.columns[0].title).toBe('Timestamp');
});
it('Value column title should be Val', () => {
expect(table.columns[1].title).to.be('Val');
expect(table.columns[1].title).toBe('Val');
});
it('Colored column title should be Colored', () => {
expect(table.columns[2].title).to.be('Colored');
expect(table.columns[2].title).toBe('Colored');
});
it('link should render as', () => {
......@@ -182,7 +180,7 @@ describe('when rendering table', () => {
</a>
</td>
`;
expect(normalize(html)).to.be(normalize(expectedHtml));
expect(normalize(html)).toBe(normalize(expectedHtml));
});
});
});
......
import {describe, beforeEach, it, expect} from 'test/lib/common';
import {transformers, transformDataToTable} from '../transformers';
describe('when transforming time series table', () => {
......@@ -29,18 +27,18 @@ describe('when transforming time series table', () => {
});
it('should return 3 rows', () => {
expect(table.rows.length).to.be(3);
expect(table.rows[0][1]).to.be('series1');
expect(table.rows[1][1]).to.be('series1');
expect(table.rows[2][1]).to.be('series2');
expect(table.rows[0][2]).to.be(12.12);
expect(table.rows.length).toBe(3);
expect(table.rows[0][1]).toBe('series1');
expect(table.rows[1][1]).toBe('series1');
expect(table.rows[2][1]).toBe('series2');
expect(table.rows[0][2]).toBe(12.12);
});
it('should return 3 rows', () => {
expect(table.columns.length).to.be(3);
expect(table.columns[0].text).to.be('Time');
expect(table.columns[1].text).to.be('Metric');
expect(table.columns[2].text).to.be('Value');
expect(table.columns.length).toBe(3);
expect(table.columns[0].text).toBe('Time');
expect(table.columns[1].text).toBe('Metric');
expect(table.columns[2].text).toBe('Value');
});
});
......@@ -54,20 +52,20 @@ describe('when transforming time series table', () => {
});
it ('should return 3 columns', () => {
expect(table.columns.length).to.be(3);
expect(table.columns[0].text).to.be('Time');
expect(table.columns[1].text).to.be('series1');
expect(table.columns[2].text).to.be('series2');
expect(table.columns.length).toBe(3);
expect(table.columns[0].text).toBe('Time');
expect(table.columns[1].text).toBe('series1');
expect(table.columns[2].text).toBe('series2');
});
it ('should return 2 rows', () => {
expect(table.rows.length).to.be(2);
expect(table.rows[0][1]).to.be(12.12);
expect(table.rows[0][2]).to.be(16.12);
expect(table.rows.length).toBe(2);
expect(table.rows[0][1]).toBe(12.12);
expect(table.rows[0][2]).toBe(16.12);
});
it ('should be undefined when no value for timestamp', () => {
expect(table.rows[1][2]).to.be(undefined);
expect(table.rows[1][2]).toBe(undefined);
});
});
......@@ -83,17 +81,17 @@ describe('when transforming time series table', () => {
});
it('should return 2 rows', () => {
expect(table.rows.length).to.be(2);
expect(table.rows[0][0]).to.be('series1');
expect(table.rows[0][1]).to.be(14.44);
expect(table.rows[0][2]).to.be(12.12);
expect(table.rows.length).toBe(2);
expect(table.rows[0][0]).toBe('series1');
expect(table.rows[0][1]).toBe(14.44);
expect(table.rows[0][2]).toBe(12.12);
});
it('should return 2 columns', () => {
expect(table.columns.length).to.be(3);
expect(table.columns[0].text).to.be('Metric');
expect(table.columns[1].text).to.be('Max');
expect(table.columns[2].text).to.be('Min');
expect(table.columns.length).toBe(3);
expect(table.columns[0].text).toBe('Metric');
expect(table.columns[1].text).toBe('Max');
expect(table.columns[2].text).toBe('Min');
});
});
......@@ -124,9 +122,9 @@ describe('when transforming time series table', () => {
describe('getColumns', function() {
it('should return nested properties', function() {
var columns = transformers['json'].getColumns(rawData);
expect(columns[0].text).to.be('timestamp');
expect(columns[1].text).to.be('message');
expect(columns[2].text).to.be('nested.level2');
expect(columns[0].text).toBe('timestamp');
expect(columns[1].text).toBe('message');
expect(columns[2].text).toBe('nested.level2');
});
});
......@@ -136,17 +134,17 @@ describe('when transforming time series table', () => {
});
it ('should return 2 columns', () => {
expect(table.columns.length).to.be(3);
expect(table.columns[0].text).to.be('Timestamp');
expect(table.columns[1].text).to.be('Message');
expect(table.columns[2].text).to.be('nested.level2');
expect(table.columns.length).toBe(3);
expect(table.columns[0].text).toBe('Timestamp');
expect(table.columns[1].text).toBe('Message');
expect(table.columns[2].text).toBe('nested.level2');
});
it ('should return 2 rows', () => {
expect(table.rows.length).to.be(1);
expect(table.rows[0][0]).to.be('time');
expect(table.rows[0][1]).to.be('message');
expect(table.rows[0][2]).to.be('level2-value');
expect(table.rows.length).toBe(1);
expect(table.rows[0][0]).toBe('time');
expect(table.rows[0][1]).toBe('message');
expect(table.rows[0][2]).toBe('level2-value');
});
});
});
......@@ -169,16 +167,16 @@ describe('when transforming time series table', () => {
});
it ('should return 4 columns', () => {
expect(table.columns.length).to.be(4);
expect(table.columns[0].text).to.be('Time');
expect(table.columns[1].text).to.be('Title');
expect(table.columns[2].text).to.be('Text');
expect(table.columns[3].text).to.be('Tags');
expect(table.columns.length).toBe(4);
expect(table.columns[0].text).toBe('Time');
expect(table.columns[1].text).toBe('Title');
expect(table.columns[2].text).toBe('Text');
expect(table.columns[3].text).toBe('Tags');
});
it ('should return 1 rows', () => {
expect(table.rows.length).to.be(1);
expect(table.rows[0][0]).to.be(1000);
expect(table.rows.length).toBe(1);
expect(table.rows[0][0]).toBe(1000);
});
});
......
///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash';
import flatten from '../../../core/utils/flatten';
import TimeSeries from '../../../core/time_series2';
......
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
declare var global: NodeJS.Global;
(<any>global).requestAnimationFrame = (callback) => {
setTimeout(callback, 0);
};
(function() {
"use strict";
// Tun on full stack traces in errors to help debugging
Error.stackTraceLimit=Infinity;
window.__karma__.loaded = function() {};
System.config({
baseURL: '/base/',
defaultJSExtensions: true,
paths: {
'mousetrap': 'vendor/npm/mousetrap/mousetrap.js',
'eventemitter3': 'vendor/npm/eventemitter3/index.js',
'remarkable': 'vendor/npm/remarkable/dist/remarkable.js',
'tether': 'vendor/npm/tether/dist/js/tether.js',
'tether-drop': 'vendor/npm/tether-drop/dist/js/drop.js',
'moment': 'vendor/moment.js',
"jquery": "vendor/jquery/dist/jquery.js",
'lodash-src': 'vendor/lodash/dist/lodash.js',
"lodash": 'app/core/lodash_extended.js',
"angular": 'vendor/angular/angular.js',
'angular-mocks': 'vendor/angular-mocks/angular-mocks.js',
"bootstrap": "vendor/bootstrap/bootstrap.js",
'angular-route': 'vendor/angular-route/angular-route.js',
'angular-sanitize': 'vendor/angular-sanitize/angular-sanitize.js',
"angular-ui": "vendor/angular-ui/ui-bootstrap-tpls.js",
"angular-strap": "vendor/angular-other/angular-strap.js",
"angular-dragdrop": "vendor/angular-native-dragdrop/draganddrop.js",
"angular-bindonce": "vendor/angular-bindonce/bindonce.js",
"spectrum": "vendor/spectrum.js",
"bootstrap-tagsinput": "vendor/tagsinput/bootstrap-tagsinput.js",
"jquery.flot": "vendor/flot/jquery.flot",
"jquery.flot.pie": "vendor/flot/jquery.flot.pie",
"jquery.flot.selection": "vendor/flot/jquery.flot.selection",
"jquery.flot.stack": "vendor/flot/jquery.flot.stack",
"jquery.flot.stackpercent": "vendor/flot/jquery.flot.stackpercent",
"jquery.flot.time": "vendor/flot/jquery.flot.time",
"jquery.flot.crosshair": "vendor/flot/jquery.flot.crosshair",
"jquery.flot.fillbelow": "vendor/flot/jquery.flot.fillbelow",
"jquery.flot.gauge": "vendor/flot/jquery.flot.gauge",
"d3": "vendor/d3/d3.js",
"jquery.flot.dashes": "vendor/flot/jquery.flot.dashes",
"twemoji": "vendor/npm/twemoji/2/twemoji.amd.js",
"ace": "vendor/npm/ace-builds/src-noconflict/ace",
},
packages: {
app: {
defaultExtension: 'js',
},
vendor: {
defaultExtension: 'js',
},
},
map: {
},
meta: {
'vendor/angular/angular.js': {
format: 'global',
deps: ['jquery'],
exports: 'angular',
},
'vendor/angular-mocks/angular-mocks.js': {
format: 'global',
deps: ['angular'],
},
'vendor/npm/eventemitter3/index.js': {
format: 'cjs',
exports: 'EventEmitter'
},
'vendor/npm/mousetrap/mousetrap.js': {
format: 'global',
exports: 'Mousetrap'
},
'vendor/npm/ace-builds/src-noconflict/ace.js': {
format: 'global',
exports: 'ace'
},
}
});
function file2moduleName(filePath) {
return filePath.replace(/\\/g, '/')
.replace(/^\/base\//, '')
.replace(/\.\w*$/, '');
}
function onlySpecFiles(path) {
return /specs.*/.test(path);
}
window.grafanaBootData = {settings: {}};
var modules = ['angular', 'angular-mocks', 'app/app'];
var promises = modules.map(function(name) {
return System.import(name);
});
Promise.all(promises).then(function(deps) {
var angular = deps[0];
angular.module('grafana', ['ngRoute']);
angular.module('grafana.services', ['ngRoute', '$strap.directives']);
angular.module('grafana.panels', []);
angular.module('grafana.controllers', []);
angular.module('grafana.directives', []);
angular.module('grafana.filters', []);
angular.module('grafana.routes', ['ngRoute']);
// load specs
return Promise.all(
Object.keys(window.__karma__.files) // All files served by Karma.
.filter(onlySpecFiles)
.map(file2moduleName)
.map(function(path) {
// console.log(path);
return System.import(path);
}));
}).then(function() {
window.__karma__.start();
}, function(error) {
window.__karma__.error(error.stack || error);
}).catch(function(error) {
window.__karma__.error(error.stack || error);
});
})();
......@@ -16,8 +16,16 @@ rm -rf node_modules
npm install -g yarn --quiet
yarn install --pure-lockfile --no-progress
exit_if_fail npm test
exit_if_fail npm build
exit_if_fail npm run test-ci
exit_if_fail npm run build
# publish code coverage
echo "Publishing javascript code coverage"
bash <(curl -s https://codecov.io/bash) -cF javascript
rm -rf coverage
# npm install -g codecov
# codecov
# cat ./coverage/lcov.info | node ./node_modules/coveralls/bin/coveralls.js
echo "running go fmt"
exit_if_fail test -z "$(gofmt -s -l ./pkg | tee /dev/stderr)"
......@@ -29,4 +37,17 @@ echo "building binaries"
exit_if_fail go run build.go build
echo "running go test"
exit_if_fail go test -v ./pkg/...
set -e
echo "" > coverage.txt
for d in $(go list ./pkg/...); do
exit_if_fail go test -race -coverprofile=profile.out -covermode=atomic $d
if [ -f profile.out ]; then
cat profile.out >> coverage.txt
rm profile.out
fi
done
echo "Publishing go code coverage"
bash <(curl -s https://codecov.io/bash) -cF go
......@@ -14,6 +14,7 @@ module.exports = function(grunt) {
'jshint',
'sasslint',
'exec:tslint',
"exec:jest",
'karma:test',
'no-only-tests'
]);
......
module.exports = function(config, grunt) {
'use strict'
var coverage = '';
if (config.coverage) {
coverage = '--coverage';
}
return {
tslint : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json --type-check",
tslint : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json",
jest : "node ./node_modules/jest-cli/bin/jest.js " + coverage,
};
};
......@@ -26,6 +26,10 @@ module.exports = merge(common, {
]
},
devServer: {
stats: 'errors-only',
},
plugins: [
new ExtractTextPlugin({
filename: 'grafana.[name].css',
......
......@@ -2,7 +2,8 @@
"rules": {
"no-string-throw": true,
"no-unused-expression": true,
"no-unused-variable": true,
"no-unused-variable": false,
"no-use-before-declare": false,
"no-duplicate-variable": true,
"curly": true,
"class-name": true,
......@@ -33,7 +34,6 @@
"no-string-literal": false,
"no-switch-case-fall-through": false,
"no-trailing-whitespace": true,
"no-use-before-declare": true,
"no-var-keyword": false,
"object-literal-sort-keys": false,
"one-line": [true,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment