datasource.test.ts 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. import '../datasource';
  2. import CloudWatchDatasource from '../datasource';
  3. import * as dateMath from 'app/core/utils/datemath';
  4. import { TemplateSrv } from 'app/features/templating/template_srv';
  5. import { CustomVariable } from 'app/features/templating/all';
  6. import _ from 'lodash';
  7. import { CloudWatchQuery } from '../types';
  8. describe('CloudWatchDatasource', () => {
  9. const instanceSettings = {
  10. jsonData: { defaultRegion: 'us-east-1', access: 'proxy' },
  11. };
  12. const templateSrv = new TemplateSrv();
  13. const timeSrv = {
  14. time: { from: 'now-1h', to: 'now' },
  15. timeRange: () => {
  16. return {
  17. from: dateMath.parse(timeSrv.time.from, false),
  18. to: dateMath.parse(timeSrv.time.to, true),
  19. };
  20. },
  21. };
  22. const backendSrv = {};
  23. const ctx = {
  24. backendSrv,
  25. templateSrv,
  26. } as any;
  27. beforeEach(() => {
  28. ctx.ds = new CloudWatchDatasource(instanceSettings, {}, backendSrv, templateSrv, timeSrv);
  29. });
  30. describe('When performing CloudWatch query', () => {
  31. let requestParams: { queries: CloudWatchQuery[] };
  32. const query = {
  33. range: { from: 'now-1h', to: 'now' },
  34. rangeRaw: { from: 1483228800, to: 1483232400 },
  35. targets: [
  36. {
  37. refId: 'A',
  38. region: 'us-east-1',
  39. namespace: 'AWS/EC2',
  40. metricName: 'CPUUtilization',
  41. dimensions: {
  42. InstanceId: 'i-12345678',
  43. },
  44. statistics: ['Average'],
  45. period: '300',
  46. },
  47. ],
  48. };
  49. const response = {
  50. timings: [null],
  51. results: {
  52. A: {
  53. error: '',
  54. refId: 'A',
  55. meta: {},
  56. series: [
  57. {
  58. name: 'CPUUtilization_Average',
  59. points: [[1, 1483228800000], [2, 1483229100000], [5, 1483229700000]],
  60. tags: {
  61. InstanceId: 'i-12345678',
  62. },
  63. },
  64. ],
  65. },
  66. },
  67. };
  68. beforeEach(() => {
  69. ctx.backendSrv.datasourceRequest = jest.fn(params => {
  70. requestParams = params.data;
  71. return Promise.resolve({ data: response });
  72. });
  73. });
  74. it('should generate the correct query', done => {
  75. ctx.ds.query(query).then(() => {
  76. const params = requestParams.queries[0];
  77. expect(params.namespace).toBe(query.targets[0].namespace);
  78. expect(params.metricName).toBe(query.targets[0].metricName);
  79. expect(params.dimensions['InstanceId']).toBe('i-12345678');
  80. expect(params.statistics).toEqual(query.targets[0].statistics);
  81. expect(params.period).toBe(query.targets[0].period);
  82. done();
  83. });
  84. });
  85. it('should generate the correct query with interval variable', done => {
  86. templateSrv.init([
  87. new CustomVariable(
  88. {
  89. name: 'period',
  90. current: {
  91. value: '10m',
  92. },
  93. multi: false,
  94. },
  95. {}
  96. ),
  97. ]);
  98. const query = {
  99. range: { from: 'now-1h', to: 'now' },
  100. rangeRaw: { from: 1483228800, to: 1483232400 },
  101. targets: [
  102. {
  103. refId: 'A',
  104. region: 'us-east-1',
  105. namespace: 'AWS/EC2',
  106. metricName: 'CPUUtilization',
  107. dimensions: {
  108. InstanceId: 'i-12345678',
  109. },
  110. statistics: ['Average'],
  111. period: '[[period]]',
  112. },
  113. ],
  114. };
  115. ctx.ds.query(query).then(() => {
  116. const params = requestParams.queries[0];
  117. expect(params.period).toBe('600');
  118. done();
  119. });
  120. });
  121. it.each(['pNN.NN', 'p9', 'p99.', 'p99.999'])('should cancel query for invalid extended statistics (%s)', stat => {
  122. const query = {
  123. range: { from: 'now-1h', to: 'now' },
  124. rangeRaw: { from: 1483228800, to: 1483232400 },
  125. targets: [
  126. {
  127. refId: 'A',
  128. region: 'us-east-1',
  129. namespace: 'AWS/EC2',
  130. metricName: 'CPUUtilization',
  131. dimensions: {
  132. InstanceId: 'i-12345678',
  133. },
  134. statistics: [stat],
  135. period: '60s',
  136. },
  137. ],
  138. };
  139. expect(ctx.ds.query.bind(ctx.ds, query)).toThrow(/Invalid extended statistics/);
  140. });
  141. it('should return series list', done => {
  142. ctx.ds.query(query).then(result => {
  143. expect(result.data[0].target).toBe(response.results.A.series[0].name);
  144. expect(result.data[0].datapoints[0][0]).toBe(response.results.A.series[0].points[0][0]);
  145. done();
  146. });
  147. });
  148. });
  149. describe('When query region is "default"', () => {
  150. it('should return the datasource region if empty or "default"', () => {
  151. const defaultRegion = instanceSettings.jsonData.defaultRegion;
  152. expect(ctx.ds.getActualRegion()).toBe(defaultRegion);
  153. expect(ctx.ds.getActualRegion('')).toBe(defaultRegion);
  154. expect(ctx.ds.getActualRegion('default')).toBe(defaultRegion);
  155. });
  156. it('should return the specified region if specified', () => {
  157. expect(ctx.ds.getActualRegion('some-fake-region-1')).toBe('some-fake-region-1');
  158. });
  159. let requestParams: { queries: CloudWatchQuery[] };
  160. beforeEach(() => {
  161. ctx.ds.performTimeSeriesQuery = jest.fn(request => {
  162. requestParams = request;
  163. return Promise.resolve({ data: {} });
  164. });
  165. });
  166. it('should query for the datasource region if empty or "default"', done => {
  167. const query = {
  168. range: { from: 'now-1h', to: 'now' },
  169. rangeRaw: { from: 1483228800, to: 1483232400 },
  170. targets: [
  171. {
  172. refId: 'A',
  173. region: 'default',
  174. namespace: 'AWS/EC2',
  175. metricName: 'CPUUtilization',
  176. dimensions: {
  177. InstanceId: 'i-12345678',
  178. },
  179. statistics: ['Average'],
  180. period: 300,
  181. },
  182. ],
  183. };
  184. ctx.ds.query(query).then(result => {
  185. expect(requestParams.queries[0].region).toBe(instanceSettings.jsonData.defaultRegion);
  186. done();
  187. });
  188. });
  189. });
  190. describe('When performing CloudWatch query for extended statistics', () => {
  191. const query = {
  192. range: { from: 'now-1h', to: 'now' },
  193. rangeRaw: { from: 1483228800, to: 1483232400 },
  194. targets: [
  195. {
  196. refId: 'A',
  197. region: 'us-east-1',
  198. namespace: 'AWS/ApplicationELB',
  199. metricName: 'TargetResponseTime',
  200. dimensions: {
  201. LoadBalancer: 'lb',
  202. TargetGroup: 'tg',
  203. },
  204. statistics: ['p90.00'],
  205. period: 300,
  206. },
  207. ],
  208. };
  209. const response = {
  210. timings: [null],
  211. results: {
  212. A: {
  213. error: '',
  214. refId: 'A',
  215. meta: {},
  216. series: [
  217. {
  218. name: 'TargetResponseTime_p90.00',
  219. points: [[1, 1483228800000], [2, 1483229100000], [5, 1483229700000]],
  220. tags: {
  221. LoadBalancer: 'lb',
  222. TargetGroup: 'tg',
  223. },
  224. },
  225. ],
  226. },
  227. },
  228. };
  229. beforeEach(() => {
  230. ctx.backendSrv.datasourceRequest = jest.fn(params => {
  231. return Promise.resolve({ data: response });
  232. });
  233. });
  234. it('should return series list', done => {
  235. ctx.ds.query(query).then(result => {
  236. expect(result.data[0].target).toBe(response.results.A.series[0].name);
  237. expect(result.data[0].datapoints[0][0]).toBe(response.results.A.series[0].points[0][0]);
  238. done();
  239. });
  240. });
  241. });
  242. describe('When performing CloudWatch query with template variables', () => {
  243. let requestParams: { queries: CloudWatchQuery[] };
  244. beforeEach(() => {
  245. templateSrv.init([
  246. new CustomVariable(
  247. {
  248. name: 'var1',
  249. current: {
  250. value: 'var1-foo',
  251. },
  252. multi: false,
  253. },
  254. {}
  255. ),
  256. new CustomVariable(
  257. {
  258. name: 'var2',
  259. current: {
  260. value: 'var2-foo',
  261. },
  262. multi: false,
  263. },
  264. {}
  265. ),
  266. new CustomVariable(
  267. {
  268. name: 'var3',
  269. options: [
  270. { selected: true, value: 'var3-foo' },
  271. { selected: false, value: 'var3-bar' },
  272. { selected: true, value: 'var3-baz' },
  273. ],
  274. current: {
  275. value: ['var3-foo', 'var3-baz'],
  276. },
  277. multi: true,
  278. },
  279. {}
  280. ),
  281. ]);
  282. ctx.backendSrv.datasourceRequest = jest.fn(params => {
  283. requestParams = params.data;
  284. return Promise.resolve({ data: {} });
  285. });
  286. });
  287. it('should generate the correct query for single template variable', done => {
  288. const query = {
  289. range: { from: 'now-1h', to: 'now' },
  290. rangeRaw: { from: 1483228800, to: 1483232400 },
  291. targets: [
  292. {
  293. refId: 'A',
  294. region: 'us-east-1',
  295. namespace: 'TestNamespace',
  296. metricName: 'TestMetricName',
  297. dimensions: {
  298. dim2: '[[var2]]',
  299. },
  300. statistics: ['Average'],
  301. period: 300,
  302. },
  303. ],
  304. };
  305. ctx.ds.query(query).then(() => {
  306. expect(requestParams.queries[0].dimensions['dim2']).toBe('var2-foo');
  307. done();
  308. });
  309. });
  310. it('should generate the correct query for multilple template variables', done => {
  311. const query = {
  312. range: { from: 'now-1h', to: 'now' },
  313. rangeRaw: { from: 1483228800, to: 1483232400 },
  314. targets: [
  315. {
  316. refId: 'A',
  317. region: 'us-east-1',
  318. namespace: 'TestNamespace',
  319. metricName: 'TestMetricName',
  320. dimensions: {
  321. dim1: '[[var1]]',
  322. dim2: '[[var2]]',
  323. dim3: '[[var3]]',
  324. },
  325. statistics: ['Average'],
  326. period: 300,
  327. },
  328. ],
  329. scopedVars: {
  330. var1: { selected: true, value: 'var1-foo' },
  331. var2: { selected: true, value: 'var2-foo' },
  332. },
  333. };
  334. ctx.ds.query(query).then(() => {
  335. expect(requestParams.queries[0].dimensions['dim1']).toBe('var1-foo');
  336. expect(requestParams.queries[0].dimensions['dim2']).toBe('var2-foo');
  337. expect(requestParams.queries[0].dimensions['dim3']).toBe('var3-foo');
  338. expect(requestParams.queries[1].dimensions['dim1']).toBe('var1-foo');
  339. expect(requestParams.queries[1].dimensions['dim2']).toBe('var2-foo');
  340. expect(requestParams.queries[1].dimensions['dim3']).toBe('var3-baz');
  341. done();
  342. });
  343. });
  344. it('should generate the correct query for multilple template variables, lack scopedVars', done => {
  345. const query = {
  346. range: { from: 'now-1h', to: 'now' },
  347. rangeRaw: { from: 1483228800, to: 1483232400 },
  348. targets: [
  349. {
  350. refId: 'A',
  351. region: 'us-east-1',
  352. namespace: 'TestNamespace',
  353. metricName: 'TestMetricName',
  354. dimensions: {
  355. dim1: '[[var1]]',
  356. dim2: '[[var2]]',
  357. dim3: '[[var3]]',
  358. },
  359. statistics: ['Average'],
  360. period: 300,
  361. },
  362. ],
  363. scopedVars: {
  364. var1: { selected: true, value: 'var1-foo' },
  365. },
  366. };
  367. ctx.ds.query(query).then(() => {
  368. expect(requestParams.queries[0].dimensions['dim1']).toBe('var1-foo');
  369. expect(requestParams.queries[0].dimensions['dim2']).toBe('var2-foo');
  370. expect(requestParams.queries[0].dimensions['dim3']).toBe('var3-foo');
  371. expect(requestParams.queries[1].dimensions['dim1']).toBe('var1-foo');
  372. expect(requestParams.queries[1].dimensions['dim2']).toBe('var2-foo');
  373. expect(requestParams.queries[1].dimensions['dim3']).toBe('var3-baz');
  374. done();
  375. });
  376. });
  377. it('should generate the correct query for multilple template variables with expression', done => {
  378. const query = {
  379. range: { from: 'now-1h', to: 'now' },
  380. rangeRaw: { from: 1483228800, to: 1483232400 },
  381. targets: [
  382. {
  383. refId: 'A',
  384. id: 'id1',
  385. region: 'us-east-1',
  386. namespace: 'TestNamespace',
  387. metricName: 'TestMetricName',
  388. dimensions: {
  389. dim1: '[[var1]]',
  390. dim2: '[[var2]]',
  391. dim3: '[[var3]]',
  392. },
  393. statistics: ['Average'],
  394. period: 300,
  395. expression: '',
  396. },
  397. {
  398. refId: 'B',
  399. id: 'id2',
  400. expression: 'METRICS("id1") * 2',
  401. dimensions: {
  402. // garbage data for fail test
  403. dim1: '[[var1]]',
  404. dim2: '[[var2]]',
  405. dim3: '[[var3]]',
  406. },
  407. statistics: [], // dummy
  408. },
  409. ],
  410. scopedVars: {
  411. var1: { selected: true, value: 'var1-foo' },
  412. var2: { selected: true, value: 'var2-foo' },
  413. },
  414. };
  415. ctx.ds.query(query).then(() => {
  416. expect(requestParams.queries.length).toBe(3);
  417. expect(requestParams.queries[0].id).toMatch(/^id1.*/);
  418. expect(requestParams.queries[0].dimensions['dim1']).toBe('var1-foo');
  419. expect(requestParams.queries[0].dimensions['dim2']).toBe('var2-foo');
  420. expect(requestParams.queries[0].dimensions['dim3']).toBe('var3-foo');
  421. expect(requestParams.queries[1].id).toMatch(/^id1.*/);
  422. expect(requestParams.queries[1].dimensions['dim1']).toBe('var1-foo');
  423. expect(requestParams.queries[1].dimensions['dim2']).toBe('var2-foo');
  424. expect(requestParams.queries[1].dimensions['dim3']).toBe('var3-baz');
  425. expect(requestParams.queries[2].id).toMatch(/^id2.*/);
  426. expect(requestParams.queries[2].expression).toBe('METRICS("id1") * 2');
  427. done();
  428. });
  429. });
  430. });
  431. function describeMetricFindQuery(query, func) {
  432. describe('metricFindQuery ' + query, () => {
  433. const scenario: any = {};
  434. scenario.setup = setupCallback => {
  435. beforeEach(() => {
  436. setupCallback();
  437. ctx.backendSrv.datasourceRequest = jest.fn(args => {
  438. scenario.request = args.data;
  439. return Promise.resolve({ data: scenario.requestResponse });
  440. });
  441. ctx.ds.metricFindQuery(query).then(args => {
  442. scenario.result = args;
  443. });
  444. });
  445. };
  446. func(scenario);
  447. });
  448. }
  449. describeMetricFindQuery('regions()', scenario => {
  450. scenario.setup(() => {
  451. scenario.requestResponse = {
  452. results: {
  453. metricFindQuery: {
  454. tables: [{ rows: [['us-east-1', 'us-east-1']] }],
  455. },
  456. },
  457. };
  458. });
  459. it('should call __GetRegions and return result', () => {
  460. expect(scenario.result[0].text).toContain('us-east-1');
  461. expect(scenario.request.queries[0].type).toBe('metricFindQuery');
  462. expect(scenario.request.queries[0].subtype).toBe('regions');
  463. });
  464. });
  465. describeMetricFindQuery('namespaces()', scenario => {
  466. scenario.setup(() => {
  467. scenario.requestResponse = {
  468. results: {
  469. metricFindQuery: {
  470. tables: [{ rows: [['AWS/EC2', 'AWS/EC2']] }],
  471. },
  472. },
  473. };
  474. });
  475. it('should call __GetNamespaces and return result', () => {
  476. expect(scenario.result[0].text).toContain('AWS/EC2');
  477. expect(scenario.request.queries[0].type).toBe('metricFindQuery');
  478. expect(scenario.request.queries[0].subtype).toBe('namespaces');
  479. });
  480. });
  481. describeMetricFindQuery('metrics(AWS/EC2)', scenario => {
  482. scenario.setup(() => {
  483. scenario.requestResponse = {
  484. results: {
  485. metricFindQuery: {
  486. tables: [{ rows: [['CPUUtilization', 'CPUUtilization']] }],
  487. },
  488. },
  489. };
  490. });
  491. it('should call __GetMetrics and return result', () => {
  492. expect(scenario.result[0].text).toBe('CPUUtilization');
  493. expect(scenario.request.queries[0].type).toBe('metricFindQuery');
  494. expect(scenario.request.queries[0].subtype).toBe('metrics');
  495. });
  496. });
  497. describeMetricFindQuery('dimension_keys(AWS/EC2)', scenario => {
  498. scenario.setup(() => {
  499. scenario.requestResponse = {
  500. results: {
  501. metricFindQuery: {
  502. tables: [{ rows: [['InstanceId', 'InstanceId']] }],
  503. },
  504. },
  505. };
  506. });
  507. it('should call __GetDimensions and return result', () => {
  508. expect(scenario.result[0].text).toBe('InstanceId');
  509. expect(scenario.request.queries[0].type).toBe('metricFindQuery');
  510. expect(scenario.request.queries[0].subtype).toBe('dimension_keys');
  511. });
  512. });
  513. describeMetricFindQuery('dimension_values(us-east-1,AWS/EC2,CPUUtilization,InstanceId)', scenario => {
  514. scenario.setup(() => {
  515. scenario.requestResponse = {
  516. results: {
  517. metricFindQuery: {
  518. tables: [{ rows: [['i-12345678', 'i-12345678']] }],
  519. },
  520. },
  521. };
  522. });
  523. it('should call __ListMetrics and return result', () => {
  524. expect(scenario.result[0].text).toContain('i-12345678');
  525. expect(scenario.request.queries[0].type).toBe('metricFindQuery');
  526. expect(scenario.request.queries[0].subtype).toBe('dimension_values');
  527. });
  528. });
  529. describeMetricFindQuery('dimension_values(default,AWS/EC2,CPUUtilization,InstanceId)', scenario => {
  530. scenario.setup(() => {
  531. scenario.requestResponse = {
  532. results: {
  533. metricFindQuery: {
  534. tables: [{ rows: [['i-12345678', 'i-12345678']] }],
  535. },
  536. },
  537. };
  538. });
  539. it('should call __ListMetrics and return result', () => {
  540. expect(scenario.result[0].text).toContain('i-12345678');
  541. expect(scenario.request.queries[0].type).toBe('metricFindQuery');
  542. expect(scenario.request.queries[0].subtype).toBe('dimension_values');
  543. });
  544. });
  545. describeMetricFindQuery('resource_arns(default,ec2:instance,{"environment":["production"]})', scenario => {
  546. scenario.setup(() => {
  547. scenario.requestResponse = {
  548. results: {
  549. metricFindQuery: {
  550. tables: [
  551. {
  552. rows: [
  553. [
  554. 'arn:aws:ec2:us-east-1:123456789012:instance/i-12345678901234567',
  555. 'arn:aws:ec2:us-east-1:123456789012:instance/i-76543210987654321',
  556. ],
  557. ],
  558. },
  559. ],
  560. },
  561. },
  562. };
  563. });
  564. it('should call __ListMetrics and return result', () => {
  565. expect(scenario.result[0].text).toContain('arn:aws:ec2:us-east-1:123456789012:instance/i-12345678901234567');
  566. expect(scenario.request.queries[0].type).toBe('metricFindQuery');
  567. expect(scenario.request.queries[0].subtype).toBe('resource_arns');
  568. });
  569. });
  570. it('should caclculate the correct period', () => {
  571. const hourSec = 60 * 60;
  572. const daySec = hourSec * 24;
  573. const start = 1483196400 * 1000;
  574. const testData: any[] = [
  575. [
  576. { period: 60, namespace: 'AWS/EC2' },
  577. { range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
  578. hourSec * 3,
  579. 60,
  580. ],
  581. [
  582. { period: null, namespace: 'AWS/EC2' },
  583. { range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
  584. hourSec * 3,
  585. 300,
  586. ],
  587. [
  588. { period: 60, namespace: 'AWS/ELB' },
  589. { range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
  590. hourSec * 3,
  591. 60,
  592. ],
  593. [
  594. { period: null, namespace: 'AWS/ELB' },
  595. { range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
  596. hourSec * 3,
  597. 60,
  598. ],
  599. [
  600. { period: 1, namespace: 'CustomMetricsNamespace' },
  601. {
  602. range: {
  603. from: new Date(start),
  604. to: new Date(start + (1440 - 1) * 1000),
  605. },
  606. },
  607. hourSec * 3 - 1,
  608. 1,
  609. ],
  610. [
  611. { period: 1, namespace: 'CustomMetricsNamespace' },
  612. { range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
  613. hourSec * 3 - 1,
  614. 60,
  615. ],
  616. [
  617. { period: 60, namespace: 'CustomMetricsNamespace' },
  618. { range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
  619. hourSec * 3,
  620. 60,
  621. ],
  622. [
  623. { period: null, namespace: 'CustomMetricsNamespace' },
  624. { range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
  625. hourSec * 3 - 1,
  626. 60,
  627. ],
  628. [
  629. { period: null, namespace: 'CustomMetricsNamespace' },
  630. { range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
  631. hourSec * 3,
  632. 60,
  633. ],
  634. [
  635. { period: null, namespace: 'CustomMetricsNamespace' },
  636. { range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
  637. daySec * 15,
  638. 60,
  639. ],
  640. [
  641. { period: null, namespace: 'CustomMetricsNamespace' },
  642. { range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
  643. daySec * 63,
  644. 300,
  645. ],
  646. [
  647. { period: null, namespace: 'CustomMetricsNamespace' },
  648. { range: { from: new Date(start), to: new Date(start + 3600 * 1000) } },
  649. daySec * 455,
  650. 3600,
  651. ],
  652. ];
  653. for (const t of testData) {
  654. const target = t[0];
  655. const options = t[1];
  656. const now = new Date(options.range.from.valueOf() + t[2] * 1000);
  657. const expected = t[3];
  658. const actual = ctx.ds.getPeriod(target, options, now);
  659. expect(actual).toBe(expected);
  660. }
  661. });
  662. });