datasource_specs.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. import "../datasource";
  2. import {describe, beforeEach, it, expect, angularMocks} from 'test/lib/common';
  3. import helpers from 'test/specs/helpers';
  4. import {CloudWatchDatasource} from "../datasource";
  5. describe('CloudWatchDatasource', function() {
  6. var ctx = new helpers.ServiceTestContext();
  7. var instanceSettings = {
  8. jsonData: {defaultRegion: 'us-east-1', access: 'proxy'},
  9. };
  10. beforeEach(angularMocks.module('grafana.core'));
  11. beforeEach(angularMocks.module('grafana.services'));
  12. beforeEach(angularMocks.module('grafana.controllers'));
  13. beforeEach(ctx.providePhase(['templateSrv', 'backendSrv']));
  14. beforeEach(angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) {
  15. ctx.$q = $q;
  16. ctx.$httpBackend = $httpBackend;
  17. ctx.$rootScope = $rootScope;
  18. ctx.ds = $injector.instantiate(CloudWatchDatasource, {instanceSettings: instanceSettings});
  19. $httpBackend.when('GET', /\.html$/).respond('');
  20. }));
  21. describe('When performing CloudWatch query', function() {
  22. var requestParams;
  23. var query = {
  24. range: { from: 'now-1h', to: 'now' },
  25. targets: [
  26. {
  27. region: 'us-east-1',
  28. namespace: 'AWS/EC2',
  29. metricName: 'CPUUtilization',
  30. dimensions: {
  31. InstanceId: 'i-12345678'
  32. },
  33. statistics: ['Average'],
  34. period: 300
  35. }
  36. ]
  37. };
  38. var response = {
  39. Datapoints: [
  40. {
  41. Average: 1,
  42. Timestamp: 'Wed Dec 31 1969 16:00:00 GMT-0800 (PST)'
  43. },
  44. {
  45. Average: 2,
  46. Timestamp: 'Wed Dec 31 1969 16:05:00 GMT-0800 (PST)'
  47. },
  48. {
  49. Average: 5,
  50. Timestamp: 'Wed Dec 31 1969 16:15:00 GMT-0800 (PST)'
  51. }
  52. ],
  53. Label: 'CPUUtilization'
  54. };
  55. beforeEach(function() {
  56. ctx.backendSrv.datasourceRequest = function(params) {
  57. requestParams = params;
  58. return ctx.$q.when({data: response});
  59. };
  60. });
  61. it('should generate the correct query', function(done) {
  62. ctx.ds.query(query).then(function() {
  63. var params = requestParams.data.parameters;
  64. expect(params.namespace).to.be(query.targets[0].namespace);
  65. expect(params.metricName).to.be(query.targets[0].metricName);
  66. expect(params.dimensions[0].Name).to.be(Object.keys(query.targets[0].dimensions)[0]);
  67. expect(params.dimensions[0].Value).to.be(query.targets[0].dimensions[Object.keys(query.targets[0].dimensions)[0]]);
  68. expect(params.statistics).to.eql(query.targets[0].statistics);
  69. expect(params.period).to.be(query.targets[0].period);
  70. done();
  71. });
  72. ctx.$rootScope.$apply();
  73. });
  74. it('should generate the correct query with interval variable', function(done) {
  75. ctx.templateSrv.data = {
  76. period: '10m'
  77. };
  78. var query = {
  79. range: { from: 'now-1h', to: 'now' },
  80. targets: [
  81. {
  82. region: 'us-east-1',
  83. namespace: 'AWS/EC2',
  84. metricName: 'CPUUtilization',
  85. dimensions: {
  86. InstanceId: 'i-12345678'
  87. },
  88. statistics: ['Average'],
  89. period: '[[period]]'
  90. }
  91. ]
  92. };
  93. ctx.ds.query(query).then(function() {
  94. var params = requestParams.data.parameters;
  95. expect(params.period).to.be(600);
  96. done();
  97. });
  98. ctx.$rootScope.$apply();
  99. });
  100. it('should return series list', function(done) {
  101. ctx.ds.query(query).then(function(result) {
  102. expect(result.data[0].target).to.be('CPUUtilization_Average');
  103. expect(result.data[0].datapoints[0][0]).to.be(response.Datapoints[0]['Average']);
  104. done();
  105. });
  106. ctx.$rootScope.$apply();
  107. });
  108. it('should return null for missing data point', function(done) {
  109. ctx.ds.query(query).then(function(result) {
  110. expect(result.data[0].datapoints[2][0]).to.be(null);
  111. done();
  112. });
  113. ctx.$rootScope.$apply();
  114. });
  115. it('should generate the correct targets by expanding template variables', function() {
  116. var templateSrv = {
  117. variables: [
  118. {
  119. name: 'instance_id',
  120. options: [
  121. { text: 'i-23456789', value: 'i-23456789', selected: false },
  122. { text: 'i-34567890', value: 'i-34567890', selected: true }
  123. ]
  124. }
  125. ],
  126. replace: function (target, scopedVars) {
  127. if (target === '$instance_id' && scopedVars['instance_id']['text'] === 'i-34567890') {
  128. return 'i-34567890';
  129. } else {
  130. return '';
  131. }
  132. },
  133. getVariableName: function (e) { return 'instance_id'; },
  134. variableExists: function (e) { return true; },
  135. containsVariable: function (str, variableName) { return str.indexOf('$' + variableName) !== -1; }
  136. };
  137. var targets = [
  138. {
  139. region: 'us-east-1',
  140. namespace: 'AWS/EC2',
  141. metricName: 'CPUUtilization',
  142. dimensions: {
  143. InstanceId: '$instance_id'
  144. },
  145. statistics: ['Average'],
  146. period: 300
  147. }
  148. ];
  149. var result = ctx.ds.expandTemplateVariable(targets, {}, templateSrv);
  150. expect(result[0].dimensions.InstanceId).to.be('i-34567890');
  151. });
  152. });
  153. describe('When performing CloudWatch query for extended statistics', function() {
  154. var requestParams;
  155. var query = {
  156. range: { from: 'now-1h', to: 'now' },
  157. targets: [
  158. {
  159. region: 'us-east-1',
  160. namespace: 'AWS/ApplicationELB',
  161. metricName: 'TargetResponseTime',
  162. dimensions: {
  163. LoadBalancer: 'lb',
  164. TargetGroup: 'tg'
  165. },
  166. statistics: ['p90.00'],
  167. period: 300
  168. }
  169. ]
  170. };
  171. var response = {
  172. Datapoints: [
  173. {
  174. ExtendedStatistics: {
  175. 'p90.00': 1
  176. },
  177. Timestamp: 'Wed Dec 31 1969 16:00:00 GMT-0800 (PST)'
  178. },
  179. {
  180. ExtendedStatistics: {
  181. 'p90.00': 2
  182. },
  183. Timestamp: 'Wed Dec 31 1969 16:05:00 GMT-0800 (PST)'
  184. },
  185. {
  186. ExtendedStatistics: {
  187. 'p90.00': 5
  188. },
  189. Timestamp: 'Wed Dec 31 1969 16:15:00 GMT-0800 (PST)'
  190. }
  191. ],
  192. Label: 'TargetResponseTime'
  193. };
  194. beforeEach(function() {
  195. ctx.backendSrv.datasourceRequest = function(params) {
  196. requestParams = params;
  197. return ctx.$q.when({data: response});
  198. };
  199. });
  200. it('should return series list', function(done) {
  201. ctx.ds.query(query).then(function(result) {
  202. expect(result.data[0].target).to.be('TargetResponseTime_p90.00');
  203. expect(result.data[0].datapoints[0][0]).to.be(response.Datapoints[0].ExtendedStatistics['p90.00']);
  204. done();
  205. });
  206. ctx.$rootScope.$apply();
  207. });
  208. });
  209. function describeMetricFindQuery(query, func) {
  210. describe('metricFindQuery ' + query, () => {
  211. let scenario: any = {};
  212. scenario.setup = setupCallback => {
  213. beforeEach(() => {
  214. setupCallback();
  215. ctx.backendSrv.datasourceRequest = args => {
  216. scenario.request = args;
  217. return ctx.$q.when({data: scenario.requestResponse });
  218. };
  219. ctx.ds.metricFindQuery(query).then(args => {
  220. scenario.result = args;
  221. });
  222. ctx.$rootScope.$apply();
  223. });
  224. };
  225. func(scenario);
  226. });
  227. }
  228. describeMetricFindQuery('regions()', scenario => {
  229. scenario.setup(() => {
  230. scenario.requestResponse = [{text: 'us-east-1'}];
  231. });
  232. it('should call __GetRegions and return result', () => {
  233. expect(scenario.result[0].text).to.contain('us-east-1');
  234. expect(scenario.request.data.action).to.be('__GetRegions');
  235. });
  236. });
  237. describeMetricFindQuery('namespaces()', scenario => {
  238. scenario.setup(() => {
  239. scenario.requestResponse = [{text: 'AWS/EC2'}];
  240. });
  241. it('should call __GetNamespaces and return result', () => {
  242. expect(scenario.result[0].text).to.contain('AWS/EC2');
  243. expect(scenario.request.data.action).to.be('__GetNamespaces');
  244. });
  245. });
  246. describeMetricFindQuery('metrics(AWS/EC2)', scenario => {
  247. scenario.setup(() => {
  248. scenario.requestResponse = [{text: 'CPUUtilization'}];
  249. });
  250. it('should call __GetMetrics and return result', () => {
  251. expect(scenario.result[0].text).to.be('CPUUtilization');
  252. expect(scenario.request.data.action).to.be('__GetMetrics');
  253. });
  254. });
  255. describeMetricFindQuery('dimension_keys(AWS/EC2)', scenario => {
  256. scenario.setup(() => {
  257. scenario.requestResponse = [{text: 'InstanceId'}];
  258. });
  259. it('should call __GetDimensions and return result', () => {
  260. expect(scenario.result[0].text).to.be('InstanceId');
  261. expect(scenario.request.data.action).to.be('__GetDimensions');
  262. });
  263. });
  264. describeMetricFindQuery('dimension_values(us-east-1,AWS/EC2,CPUUtilization,InstanceId)', scenario => {
  265. scenario.setup(() => {
  266. scenario.requestResponse = {
  267. Metrics: [
  268. {
  269. Namespace: 'AWS/EC2',
  270. MetricName: 'CPUUtilization',
  271. Dimensions: [
  272. {
  273. Name: 'InstanceId',
  274. Value: 'i-12345678'
  275. }
  276. ]
  277. }
  278. ]
  279. };
  280. });
  281. it('should call __ListMetrics and return result', () => {
  282. expect(scenario.result[0].text).to.be('i-12345678');
  283. expect(scenario.request.data.action).to.be('ListMetrics');
  284. });
  285. });
  286. it('should caclculate the correct period', function () {
  287. var hourSec = 60 * 60;
  288. var daySec = hourSec * 24;
  289. var start = 1483196400;
  290. var testData: any[] = [
  291. [{ period: 60 }, { namespace: 'AWS/EC2' }, {}, start, start + 3600, (hourSec * 3), 60],
  292. [{ period: null }, { namespace: 'AWS/EC2' }, {}, start, start + 3600, (hourSec * 3), 300],
  293. [{ period: 60 }, { namespace: 'AWS/ELB' }, {}, start, start + 3600, (hourSec * 3), 60],
  294. [{ period: null }, { namespace: 'AWS/ELB' }, {}, start, start + 3600, (hourSec * 3), 60],
  295. [{ period: 1 }, { namespace: 'CustomMetricsNamespace' }, {}, start, start + 1440 - 1, (hourSec * 3 - 1), 1],
  296. [{ period: 1 }, { namespace: 'CustomMetricsNamespace' }, {}, start, start + 3600, (hourSec * 3 - 1), 60],
  297. [{ period: 60 }, { namespace: 'CustomMetricsNamespace' }, {}, start, start + 3600, (hourSec * 3), 60],
  298. [{ period: null }, { namespace: 'CustomMetricsNamespace' }, {}, start, start + 3600, (hourSec * 3 - 1), 60],
  299. [{ period: null }, { namespace: 'CustomMetricsNamespace' }, {}, start, start + 3600, (hourSec * 3), 60],
  300. [{ period: null }, { namespace: 'CustomMetricsNamespace' }, {}, start, start + 3600, (daySec * 15), 60],
  301. [{ period: null }, { namespace: 'CustomMetricsNamespace' }, {}, start, start + 3600, (daySec * 63), 300],
  302. [{ period: null }, { namespace: 'CustomMetricsNamespace' }, {}, start, start + 3600, (daySec * 455), 3600]
  303. ];
  304. for (let t of testData) {
  305. let target = t[0];
  306. let query = t[1];
  307. let options = t[2];
  308. let start = t[3];
  309. let end = t[4];
  310. let now = start + t[5];
  311. let expected = t[6];
  312. let actual = ctx.ds.getPeriod(target, query, options, start, end, now);
  313. expect(actual).to.be(expected);
  314. }
  315. });
  316. describeMetricFindQuery('ec2_instance_attribute(us-east-1, Tags.Name, { "tag:team": [ "sysops" ] })', scenario => {
  317. scenario.setup(() => {
  318. scenario.requestResponse = {
  319. Reservations: [
  320. {
  321. Instances: [
  322. {
  323. Tags: [
  324. { Key: 'InstanceId', Value: 'i-123456' },
  325. { Key: 'Name', Value: 'Sysops Dev Server' },
  326. { Key: 'env', Value: 'dev' },
  327. { Key: 'team', Value: 'sysops' }
  328. ]
  329. },
  330. {
  331. Tags: [
  332. { Key: 'InstanceId', Value: 'i-789012' },
  333. { Key: 'Name', Value: 'Sysops Staging Server' },
  334. { Key: 'env', Value: 'staging' },
  335. { Key: 'team', Value: 'sysops' }
  336. ]
  337. }
  338. ]
  339. }
  340. ]
  341. };
  342. });
  343. it('should return the "Name" tag for each instance', function() {
  344. expect(scenario.result[0].text).to.be('Sysops Dev Server');
  345. expect(scenario.result[1].text).to.be('Sysops Staging Server');
  346. });
  347. });
  348. });