mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
added lexer/parser support for templated metric expressions, karma test runner is working
This commit is contained in:
parent
9480077f02
commit
cef4349b2a
@ -82,13 +82,24 @@ function (angular, _, config, graphiteFuncs, Parser) {
|
|||||||
|
|
||||||
$scope.segments = _.map(astNode.segments, function(segment) {
|
$scope.segments = _.map(astNode.segments, function(segment) {
|
||||||
return {
|
return {
|
||||||
|
type: segment.type,
|
||||||
val: segment.value,
|
val: segment.value,
|
||||||
html: segment.value === '*' ? '<i class="icon-asterisk"><i>' : segment.value
|
html: getSegmentHtml(segment)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSegmentHtml(segment) {
|
||||||
|
if (segment.value === '*') {
|
||||||
|
return '<i class="icon-asterisk"><i>';
|
||||||
|
}
|
||||||
|
if (segment.type === 'template') {
|
||||||
|
return "<span style='color: #ECEC09'>[[" + segment.value + "]]</span>";
|
||||||
|
}
|
||||||
|
return segment.value;
|
||||||
|
}
|
||||||
|
|
||||||
function getSegmentPathUpTo(index) {
|
function getSegmentPathUpTo(index) {
|
||||||
var arr = $scope.segments.slice(0, index);
|
var arr = $scope.segments.slice(0, index);
|
||||||
|
|
||||||
|
@ -182,6 +182,7 @@ define([
|
|||||||
|
|
||||||
match =
|
match =
|
||||||
this.scanIdentifier() ||
|
this.scanIdentifier() ||
|
||||||
|
this.scanTemplateSequence() ||
|
||||||
this.scanPunctuator() ||
|
this.scanPunctuator() ||
|
||||||
this.scanNumericLiteral();
|
this.scanNumericLiteral();
|
||||||
|
|
||||||
@ -194,6 +195,26 @@ define([
|
|||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
scanTemplateSequence: function() {
|
||||||
|
if (this.peek() === '[' && this.peek(1) === '[') {
|
||||||
|
return {
|
||||||
|
type: 'templateStart',
|
||||||
|
value: '[[',
|
||||||
|
pos: this.char
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.peek() === ']' && this.peek(1) === ']') {
|
||||||
|
return {
|
||||||
|
type: 'templateEnd',
|
||||||
|
value: '[[',
|
||||||
|
pos: this.char
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract a JavaScript identifier out of the next sequence of
|
* Extract a JavaScript identifier out of the next sequence of
|
||||||
* characters or return 'null' if its not possible. In addition,
|
* characters or return 'null' if its not possible. In addition,
|
||||||
|
@ -29,29 +29,61 @@ define([
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
metricExpression: function() {
|
metricSegment: function() {
|
||||||
|
if (this.match('identifier')) {
|
||||||
|
this.index++;
|
||||||
|
return {
|
||||||
|
type: 'segment',
|
||||||
|
value: this.tokens[this.index-1].value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.match('templateStart')) {
|
||||||
|
this.errorMark('Expected metric identifier');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.index++;
|
||||||
|
|
||||||
if (!this.match('identifier')) {
|
if (!this.match('identifier')) {
|
||||||
|
this.errorMark('Expected identifier after templateStart');
|
||||||
|
}
|
||||||
|
|
||||||
|
var node = {
|
||||||
|
type: 'template',
|
||||||
|
value: this.tokens[this.index].value
|
||||||
|
};
|
||||||
|
|
||||||
|
this.index++;
|
||||||
|
|
||||||
|
if (!this.match('templateEnd')) {
|
||||||
|
this.errorMark('Expected templateEnd');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.index++;
|
||||||
|
return node;
|
||||||
|
},
|
||||||
|
|
||||||
|
metricExpression: function() {
|
||||||
|
if (!this.match('templateStart') && !this.match('identifier')) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var node = {
|
var node = {
|
||||||
type: 'metric',
|
type: 'metric',
|
||||||
segments: [{
|
segments: []
|
||||||
type: 'segment',
|
|
||||||
value: this.tokens[this.index].value
|
|
||||||
}]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.index++;
|
node.segments.push(this.metricSegment());
|
||||||
|
|
||||||
if (this.match('.')) {
|
while(this.match('.')) {
|
||||||
this.index++;
|
this.index++;
|
||||||
var rest = this.metricExpression();
|
|
||||||
if (!rest) {
|
var segment = this.metricSegment();
|
||||||
|
if (!segment) {
|
||||||
this.errorMark('Expected metric identifier');
|
this.errorMark('Expected metric identifier');
|
||||||
}
|
}
|
||||||
|
|
||||||
node.segments = node.segments.concat(rest.segments);
|
node.segments.push(segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
|
27
src/test/karma.conf.js
Normal file
27
src/test/karma.conf.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
module.exports = function(config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '../',
|
||||||
|
|
||||||
|
frameworks: ['mocha', 'requirejs', 'expect'],
|
||||||
|
|
||||||
|
// list of files / patterns to load in the browser
|
||||||
|
files: [
|
||||||
|
'test/test-main.js',
|
||||||
|
{pattern: 'app/**/*.js', included: false},
|
||||||
|
{pattern: 'test/**/*.js', included: false}
|
||||||
|
],
|
||||||
|
|
||||||
|
// list of files to exclude
|
||||||
|
exclude: [
|
||||||
|
],
|
||||||
|
|
||||||
|
reporters: ['progress'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: true,
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
captureTimeout: 60000,
|
||||||
|
singleRun: false
|
||||||
|
});
|
||||||
|
};
|
@ -30,6 +30,15 @@ define([
|
|||||||
expect(tokens[tokens.length - 1].value).to.be(')');
|
expect(tokens[tokens.length - 1].value).to.be(')');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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('templateStart');
|
||||||
|
expect(tokens[3].type).to.be('identifier');
|
||||||
|
expect(tokens[3].value).to.be('server');
|
||||||
|
expect(tokens[4].type).to.be('templateEnd');
|
||||||
|
});
|
||||||
|
|
||||||
it('should handle error with unterminated string', function() {
|
it('should handle error with unterminated string', function() {
|
||||||
var lexer = new Lexer("alias(metric, 'asd)");
|
var lexer = new Lexer("alias(metric, 'asd)");
|
||||||
var tokens = lexer.tokenize();
|
var tokens = lexer.tokenize();
|
||||||
|
@ -54,6 +54,15 @@ define([
|
|||||||
expect(rootNode.params[1].type).to.be('metric');
|
expect(rootNode.params[1].type).to.be('metric');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('function with templated series', function() {
|
||||||
|
var parser = new Parser("sum(test.[[server]].count)");
|
||||||
|
var rootNode = parser.getAst();
|
||||||
|
|
||||||
|
expect(rootNode.message).to.be(undefined)
|
||||||
|
expect(rootNode.params[0].type).to.be('metric');
|
||||||
|
expect(rootNode.params[0].segments[1].type).to.be('template');
|
||||||
|
});
|
||||||
|
|
||||||
it('invalid metric expression', function() {
|
it('invalid metric expression', function() {
|
||||||
var parser = new Parser('metric.test.*.asd.');
|
var parser = new Parser('metric.test.*.asd.');
|
||||||
var rootNode = parser.getAst();
|
var rootNode = parser.getAst();
|
||||||
|
10
src/test/test-main.js
Normal file
10
src/test/test-main.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
require.config({
|
||||||
|
baseUrl:'base'
|
||||||
|
});
|
||||||
|
|
||||||
|
require([
|
||||||
|
'test/specs/lexer-specs',
|
||||||
|
'test/specs/parser-specs',
|
||||||
|
], function () {
|
||||||
|
window.__karma__.start();
|
||||||
|
});
|
9
tasks/options/karma.js
Normal file
9
tasks/options/karma.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module.exports = function(config) {
|
||||||
|
return {
|
||||||
|
unit: {
|
||||||
|
configFile: 'src/test/karma.conf.js',
|
||||||
|
singleRun: false,
|
||||||
|
browsers: ['Chrome']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user