singlestat.test.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. import { SingleStatCtrl, ShowData } from '../module';
  2. import { dateTime, ReducerID } from '@grafana/data';
  3. import { LinkSrv } from 'app/features/panel/panellinks/link_srv';
  4. import { LegacyResponseData } from '@grafana/ui';
  5. interface TestContext {
  6. ctrl: SingleStatCtrl;
  7. input: LegacyResponseData[];
  8. data: Partial<ShowData>;
  9. setup: (setupFunc: any) => void;
  10. }
  11. describe('SingleStatCtrl', () => {
  12. const ctx: TestContext = {} as TestContext;
  13. const epoch = 1505826363746;
  14. Date.now = () => epoch;
  15. const $scope = {
  16. $on: () => {},
  17. };
  18. const $injector = {
  19. get: () => {},
  20. };
  21. const $sanitize = {};
  22. SingleStatCtrl.prototype.panel = {
  23. events: {
  24. on: () => {},
  25. emit: () => {},
  26. },
  27. };
  28. SingleStatCtrl.prototype.dashboard = {
  29. isTimezoneUtc: jest.fn(() => true),
  30. };
  31. SingleStatCtrl.prototype.events = {
  32. on: () => {},
  33. };
  34. function singleStatScenario(desc: string, func: any) {
  35. describe(desc, () => {
  36. ctx.setup = (setupFunc: any) => {
  37. beforeEach(() => {
  38. // @ts-ignore
  39. ctx.ctrl = new SingleStatCtrl($scope, $injector, {} as LinkSrv, $sanitize);
  40. setupFunc();
  41. ctx.ctrl.onDataReceived(ctx.input);
  42. ctx.data = ctx.ctrl.data;
  43. });
  44. };
  45. func(ctx);
  46. });
  47. }
  48. singleStatScenario('with defaults', (ctx: TestContext) => {
  49. ctx.setup(() => {
  50. ctx.input = [{ target: 'test.cpu1', datapoints: [[10, 1], [20, 2]] }];
  51. });
  52. it('Should use series avg as default main value', () => {
  53. expect(ctx.data.value).toBe(15);
  54. });
  55. it('should set formatted falue', () => {
  56. expect(ctx.data.display.text).toBe('15');
  57. });
  58. });
  59. singleStatScenario('showing serie name instead of value', (ctx: TestContext) => {
  60. ctx.setup(() => {
  61. ctx.input = [{ target: 'test.cpu1', datapoints: [[10, 1], [20, 2]] }];
  62. ctx.ctrl.panel.valueName = 'name';
  63. });
  64. it('Should use series avg as default main value', () => {
  65. expect(ctx.data.value).toBe('test.cpu1');
  66. });
  67. it('should set formatted value', () => {
  68. expect(ctx.data.display.text).toBe('test.cpu1');
  69. });
  70. });
  71. singleStatScenario('showing last iso time instead of value', (ctx: TestContext) => {
  72. ctx.setup(() => {
  73. ctx.input = [{ target: 'test.cpu1', datapoints: [[10, 12], [20, 1505634997920]] }];
  74. ctx.ctrl.panel.valueName = 'last_time';
  75. ctx.ctrl.panel.format = 'dateTimeAsIso';
  76. ctx.ctrl.dashboard.isTimezoneUtc = () => false;
  77. });
  78. it('Should use time instead of value', () => {
  79. expect(ctx.data.value).toBe(1505634997920);
  80. });
  81. it('should set formatted value', () => {
  82. expect(dateTime(ctx.data.display.text).valueOf()).toBe(1505634997000);
  83. });
  84. });
  85. singleStatScenario('showing last iso time instead of value (in UTC)', (ctx: TestContext) => {
  86. ctx.setup(() => {
  87. ctx.input = [{ target: 'test.cpu1', datapoints: [[10, 12], [20, 5000]] }];
  88. ctx.ctrl.panel.valueName = 'last_time';
  89. ctx.ctrl.panel.format = 'dateTimeAsIso';
  90. ctx.ctrl.dashboard.isTimezoneUtc = () => true;
  91. });
  92. it('should set value', () => {
  93. expect(ctx.data.display.text).toBe('1970-01-01 00:00:05');
  94. });
  95. });
  96. singleStatScenario('showing last us time instead of value', (ctx: TestContext) => {
  97. ctx.setup(() => {
  98. ctx.input = [{ target: 'test.cpu1', datapoints: [[10, 12], [20, 1505634997920]] }];
  99. ctx.ctrl.panel.valueName = 'last_time';
  100. ctx.ctrl.panel.format = 'dateTimeAsUS';
  101. ctx.ctrl.dashboard.isTimezoneUtc = () => false;
  102. });
  103. it('Should use time instead of value', () => {
  104. expect(ctx.data.value).toBe(1505634997920);
  105. });
  106. it('should set formatted value', () => {
  107. expect(ctx.data.display.text).toBe(dateTime(1505634997920).format('MM/DD/YYYY h:mm:ss a'));
  108. });
  109. });
  110. singleStatScenario('showing last us time instead of value (in UTC)', (ctx: TestContext) => {
  111. ctx.setup(() => {
  112. ctx.input = [{ target: 'test.cpu1', datapoints: [[10, 12], [20, 5000]] }];
  113. ctx.ctrl.panel.valueName = 'last_time';
  114. ctx.ctrl.panel.format = 'dateTimeAsUS';
  115. ctx.ctrl.dashboard.isTimezoneUtc = () => true;
  116. });
  117. it('should set formatted value', () => {
  118. expect(ctx.data.display.text).toBe('01/01/1970 12:00:05 am');
  119. });
  120. });
  121. singleStatScenario('showing last time from now instead of value', (ctx: TestContext) => {
  122. ctx.setup(() => {
  123. ctx.input = [{ target: 'test.cpu1', datapoints: [[10, 12], [20, 1505634997920]] }];
  124. ctx.ctrl.panel.valueName = 'last_time';
  125. ctx.ctrl.panel.format = 'dateTimeFromNow';
  126. });
  127. it('Should use time instead of value', () => {
  128. expect(ctx.data.value).toBe(1505634997920);
  129. });
  130. it('should set formatted value', () => {
  131. expect(ctx.data.display.text).toBe('2 days ago');
  132. });
  133. });
  134. singleStatScenario('showing last time from now instead of value (in UTC)', (ctx: TestContext) => {
  135. ctx.setup(() => {
  136. ctx.input = [{ target: 'test.cpu1', datapoints: [[10, 12], [20, 1505634997920]] }];
  137. ctx.ctrl.panel.valueName = 'last_time';
  138. ctx.ctrl.panel.format = 'dateTimeFromNow';
  139. });
  140. it('should set formatted value', () => {
  141. expect(ctx.data.display.text).toBe('2 days ago');
  142. });
  143. });
  144. singleStatScenario(
  145. 'MainValue should use same number for decimals as displayed when checking thresholds',
  146. (ctx: TestContext) => {
  147. ctx.setup(() => {
  148. ctx.input = [{ target: 'test.cpu1', datapoints: [[99.999, 1], [99.99999, 2]] }];
  149. ctx.ctrl.panel.valueName = 'avg';
  150. ctx.ctrl.panel.format = 'none';
  151. });
  152. it('Should be rounded', () => {
  153. expect(ctx.data.value).toBe(99.999495);
  154. });
  155. it('should set formatted value', () => {
  156. expect(ctx.data.display.text).toBe('100');
  157. });
  158. }
  159. );
  160. singleStatScenario('When value to text mapping is specified', (ctx: TestContext) => {
  161. ctx.setup(() => {
  162. ctx.input = [{ target: 'test.cpu1', datapoints: [[9.9, 1]] }];
  163. ctx.ctrl.panel.valueMaps = [{ value: '10', text: 'OK' }];
  164. });
  165. it('value should remain', () => {
  166. expect(ctx.data.value).toBe(9.9);
  167. });
  168. it('Should replace value with text', () => {
  169. expect(ctx.data.display.text).toBe('OK');
  170. });
  171. });
  172. singleStatScenario('When range to text mapping is specified for first range', (ctx: TestContext) => {
  173. ctx.setup(() => {
  174. ctx.input = [{ target: 'test.cpu1', datapoints: [[41, 50]] }];
  175. ctx.ctrl.panel.mappingType = 2;
  176. ctx.ctrl.panel.rangeMaps = [{ from: '10', to: '50', text: 'OK' }, { from: '51', to: '100', text: 'NOT OK' }];
  177. });
  178. it('Should replace value with text OK', () => {
  179. expect(ctx.data.display.text).toBe('OK');
  180. });
  181. });
  182. singleStatScenario('When range to text mapping is specified for other ranges', (ctx: TestContext) => {
  183. ctx.setup(() => {
  184. ctx.input = [{ target: 'test.cpu1', datapoints: [[65, 75]] }];
  185. ctx.ctrl.panel.mappingType = 2;
  186. ctx.ctrl.panel.rangeMaps = [{ from: '10', to: '50', text: 'OK' }, { from: '51', to: '100', text: 'NOT OK' }];
  187. });
  188. it('Should replace value with text NOT OK', () => {
  189. expect(ctx.data.display.text).toBe('NOT OK');
  190. });
  191. });
  192. describe('When table data', () => {
  193. const tableData = [
  194. {
  195. columns: [{ text: 'Time', type: 'time' }, { text: 'test1' }, { text: 'mean' }, { text: 'test2' }],
  196. rows: [[1492759673649, 'ignore1', 15, 'ignore2']],
  197. type: 'table',
  198. },
  199. ];
  200. singleStatScenario('with default values', (ctx: TestContext) => {
  201. ctx.setup(() => {
  202. ctx.input = tableData;
  203. ctx.ctrl.panel = {
  204. emit: () => {},
  205. };
  206. ctx.ctrl.panel.tableColumn = 'mean';
  207. ctx.ctrl.panel.format = 'none';
  208. });
  209. it('Should use first rows value as default main value', () => {
  210. expect(ctx.data.value).toBe(15);
  211. });
  212. it('should set formatted value', () => {
  213. expect(ctx.data.display.text).toBe('15');
  214. });
  215. });
  216. singleStatScenario('When table data has multiple columns', (ctx: TestContext) => {
  217. ctx.setup(() => {
  218. ctx.input = tableData;
  219. ctx.ctrl.panel.tableColumn = '';
  220. });
  221. it('Should set column to first column that is not time', () => {
  222. expect(ctx.ctrl.panel.tableColumn).toBe('test1');
  223. });
  224. });
  225. singleStatScenario(
  226. 'MainValue should use same number for decimals as displayed when checking thresholds',
  227. (ctx: TestContext) => {
  228. ctx.setup(() => {
  229. ctx.input = tableData;
  230. ctx.input[0].rows[0] = [1492759673649, 'ignore1', 99.99999, 'ignore2'];
  231. ctx.ctrl.panel.mappingType = 0;
  232. ctx.ctrl.panel.tableColumn = 'mean';
  233. });
  234. it('Should be rounded', () => {
  235. expect(ctx.data.value).toBe(99.99999);
  236. });
  237. it('should set formatted falue', () => {
  238. expect(ctx.data.display.text).toBe('100');
  239. });
  240. }
  241. );
  242. singleStatScenario('When value to text mapping is specified', (ctx: TestContext) => {
  243. ctx.setup(() => {
  244. ctx.input = tableData;
  245. ctx.input[0].rows[0] = [1492759673649, 'ignore1', 9.9, 'ignore2'];
  246. ctx.ctrl.panel.mappingType = 2;
  247. ctx.ctrl.panel.tableColumn = 'mean';
  248. ctx.ctrl.panel.valueMaps = [{ value: '10', text: 'OK' }];
  249. });
  250. it('value should remain', () => {
  251. expect(ctx.data.value).toBe(9.9);
  252. });
  253. // it('round should be rounded up', () => {
  254. // expect(ctx.data.valueRounded).toBe(10);
  255. // });
  256. it('Should replace value with text', () => {
  257. expect(ctx.data.display.text).toBe('OK');
  258. });
  259. });
  260. singleStatScenario('When range to text mapping is specified for first range', (ctx: TestContext) => {
  261. ctx.setup(() => {
  262. ctx.input = tableData;
  263. ctx.input[0].rows[0] = [1492759673649, 'ignore1', 41, 'ignore2'];
  264. ctx.ctrl.panel.tableColumn = 'mean';
  265. ctx.ctrl.panel.mappingType = 2;
  266. ctx.ctrl.panel.rangeMaps = [{ from: '10', to: '50', text: 'OK' }, { from: '51', to: '100', text: 'NOT OK' }];
  267. });
  268. it('Should replace value with text OK', () => {
  269. expect(ctx.data.display.text).toBe('OK');
  270. });
  271. });
  272. singleStatScenario('When range to text mapping is specified for other ranges', (ctx: TestContext) => {
  273. ctx.setup(() => {
  274. ctx.input = tableData;
  275. ctx.input[0].rows[0] = [1492759673649, 'ignore1', 65, 'ignore2'];
  276. ctx.ctrl.panel.tableColumn = 'mean';
  277. ctx.ctrl.panel.mappingType = 2;
  278. ctx.ctrl.panel.rangeMaps = [{ from: '10', to: '50', text: 'OK' }, { from: '51', to: '100', text: 'NOT OK' }];
  279. });
  280. it('Should replace value with text NOT OK', () => {
  281. expect(ctx.data.display.text).toBe('NOT OK');
  282. });
  283. });
  284. singleStatScenario('When value is string', (ctx: TestContext) => {
  285. ctx.setup(() => {
  286. ctx.input = tableData;
  287. ctx.input[0].rows[0] = [1492759673649, 'ignore1', 65, 'ignore2'];
  288. ctx.ctrl.panel.tableColumn = 'test1';
  289. ctx.ctrl.panel.valueName = ReducerID.first;
  290. });
  291. it('Should replace value with text NOT OK', () => {
  292. expect(ctx.data.display.text).toBe('ignore1');
  293. });
  294. });
  295. singleStatScenario('When value is zero', (ctx: TestContext) => {
  296. ctx.setup(() => {
  297. ctx.input = tableData;
  298. ctx.input[0].rows[0] = [1492759673649, 'ignore1', 0, 'ignore2'];
  299. ctx.ctrl.panel.tableColumn = 'mean';
  300. });
  301. it('Should return zero', () => {
  302. expect(ctx.data.value).toBe(0);
  303. });
  304. });
  305. });
  306. });