ResultProcessor.test.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. jest.mock('@grafana/data/src/utils/moment_wrapper', () => ({
  2. dateTime: (ts: any) => {
  3. return {
  4. valueOf: () => ts,
  5. fromNow: () => 'fromNow() jest mocked',
  6. format: (fmt: string) => 'format() jest mocked',
  7. };
  8. },
  9. toUtc: (ts: any) => {
  10. return {
  11. format: (fmt: string) => 'format() jest mocked',
  12. };
  13. },
  14. }));
  15. import { ResultProcessor } from './ResultProcessor';
  16. import { ExploreItemState, ExploreMode } from 'app/types/explore';
  17. import TableModel from 'app/core/table_model';
  18. import {
  19. TimeSeries,
  20. LogRowModel,
  21. LogsMetaItem,
  22. GraphSeriesXY,
  23. MutableDataFrame,
  24. toDataFrame,
  25. FieldType,
  26. } from '@grafana/data';
  27. const testContext = (options: any = {}) => {
  28. const timeSeries = toDataFrame({
  29. name: 'A-series',
  30. refId: 'A',
  31. fields: [
  32. { name: 'A-series', type: FieldType.number, values: [4, 5, 6] },
  33. { name: 'time', type: FieldType.time, values: [100, 200, 300] },
  34. ],
  35. });
  36. const table = toDataFrame({
  37. name: 'table-res',
  38. refId: 'A',
  39. fields: [
  40. { name: 'value', type: FieldType.number, values: [4, 5, 6] },
  41. { name: 'time', type: FieldType.time, values: [100, 200, 300] },
  42. { name: 'message', type: FieldType.string, values: ['this is a message', 'second message', 'third'] },
  43. ],
  44. });
  45. const defaultOptions = {
  46. mode: ExploreMode.Metrics,
  47. replacePreviousResults: true,
  48. dataFrames: [timeSeries, table],
  49. graphResult: [] as TimeSeries[],
  50. tableResult: new TableModel(),
  51. logsResult: { hasUniqueLabels: false, rows: [] as LogRowModel[] },
  52. };
  53. const combinedOptions = { ...defaultOptions, ...options };
  54. const state = ({
  55. mode: combinedOptions.mode,
  56. graphResult: combinedOptions.graphResult,
  57. tableResult: combinedOptions.tableResult,
  58. logsResult: combinedOptions.logsResult,
  59. queryIntervals: { intervalMs: 10 },
  60. } as any) as ExploreItemState;
  61. const resultProcessor = new ResultProcessor(
  62. state,
  63. combinedOptions.replacePreviousResults,
  64. combinedOptions.dataFrames
  65. );
  66. return {
  67. dataFrames: combinedOptions.dataFrames,
  68. resultProcessor,
  69. };
  70. };
  71. describe('ResultProcessor', () => {
  72. describe('constructed without result', () => {
  73. describe('when calling getGraphResult', () => {
  74. it('then it should return an empty array', () => {
  75. const { resultProcessor } = testContext({ dataFrames: [] });
  76. const theResult = resultProcessor.getGraphResult();
  77. expect(theResult).toEqual([]);
  78. });
  79. });
  80. describe('when calling getTableResult', () => {
  81. it('then it should return an empty TableModel', () => {
  82. const { resultProcessor } = testContext({ dataFrames: [] });
  83. const theResult = resultProcessor.getTableResult();
  84. expect(theResult).toEqual(new TableModel());
  85. });
  86. });
  87. describe('when calling getLogsResult', () => {
  88. it('then it should return null', () => {
  89. const { resultProcessor } = testContext({ dataFrames: [] });
  90. const theResult = resultProcessor.getLogsResult();
  91. expect(theResult).toBeNull();
  92. });
  93. });
  94. });
  95. describe('constructed with a result that is a DataQueryResponse', () => {
  96. describe('when calling getGraphResult', () => {
  97. it('then it should return correct graph result', () => {
  98. const { resultProcessor } = testContext();
  99. const theResult = resultProcessor.getGraphResult();
  100. expect(theResult).toEqual([
  101. {
  102. label: 'A-series',
  103. color: '#7EB26D',
  104. data: [[100, 4], [200, 5], [300, 6]],
  105. info: undefined,
  106. isVisible: true,
  107. yAxis: {
  108. index: 1,
  109. },
  110. },
  111. ]);
  112. });
  113. });
  114. describe('when calling getTableResult', () => {
  115. it('then it should return correct table result', () => {
  116. const { resultProcessor } = testContext();
  117. const theResult = resultProcessor.getTableResult();
  118. expect(theResult).toEqual({
  119. columnMap: {},
  120. columns: [
  121. { text: 'value', type: 'number', filterable: undefined },
  122. { text: 'time', type: 'time', filterable: undefined },
  123. { text: 'message', type: 'string', filterable: undefined },
  124. ],
  125. rows: [[4, 100, 'this is a message'], [5, 200, 'second message'], [6, 300, 'third']],
  126. type: 'table',
  127. });
  128. });
  129. });
  130. describe('when calling getLogsResult', () => {
  131. it('then it should return correct logs result', () => {
  132. const { resultProcessor } = testContext({ mode: ExploreMode.Logs });
  133. const theResult = resultProcessor.getLogsResult();
  134. expect(theResult).toEqual({
  135. hasUniqueLabels: false,
  136. meta: [],
  137. rows: [
  138. {
  139. entry: 'third',
  140. hasAnsi: false,
  141. labels: undefined,
  142. logLevel: 'unknown',
  143. raw: 'third',
  144. searchWords: [] as string[],
  145. timeEpochMs: 300,
  146. timeFromNow: 'fromNow() jest mocked',
  147. timeLocal: 'format() jest mocked',
  148. timeUtc: 'format() jest mocked',
  149. timestamp: 300,
  150. uniqueLabels: {},
  151. },
  152. {
  153. entry: 'second message',
  154. hasAnsi: false,
  155. labels: undefined,
  156. logLevel: 'unknown',
  157. raw: 'second message',
  158. searchWords: [] as string[],
  159. timeEpochMs: 200,
  160. timeFromNow: 'fromNow() jest mocked',
  161. timeLocal: 'format() jest mocked',
  162. timeUtc: 'format() jest mocked',
  163. timestamp: 200,
  164. uniqueLabels: {},
  165. },
  166. {
  167. entry: 'this is a message',
  168. hasAnsi: false,
  169. labels: undefined,
  170. logLevel: 'unknown',
  171. raw: 'this is a message',
  172. searchWords: [] as string[],
  173. timeEpochMs: 100,
  174. timeFromNow: 'fromNow() jest mocked',
  175. timeLocal: 'format() jest mocked',
  176. timeUtc: 'format() jest mocked',
  177. timestamp: 100,
  178. uniqueLabels: {},
  179. },
  180. ],
  181. series: [
  182. {
  183. label: 'A-series',
  184. color: '#7EB26D',
  185. data: [[100, 4], [200, 5], [300, 6]],
  186. info: undefined,
  187. isVisible: true,
  188. yAxis: {
  189. index: 1,
  190. },
  191. },
  192. ],
  193. });
  194. });
  195. });
  196. });
  197. describe('constructed with result that is a DataQueryResponse and merging with previous results', () => {
  198. describe('when calling getLogsResult', () => {
  199. it('then it should return correct logs result', () => {
  200. const { resultProcessor } = testContext({
  201. mode: ExploreMode.Logs,
  202. replacePreviousResults: false,
  203. logsResult: {
  204. hasUniqueLabels: false,
  205. meta: [],
  206. rows: [
  207. {
  208. entry: 'This is a previous message 1',
  209. fresh: true,
  210. hasAnsi: false,
  211. labels: { cluster: 'some-cluster' },
  212. logLevel: 'unknown',
  213. raw: 'This is a previous message 1',
  214. searchWords: [] as string[],
  215. timeEpochMs: 1558038519831,
  216. timeFromNow: 'fromNow() jest mocked',
  217. timeLocal: 'format() jest mocked',
  218. timeUtc: 'format() jest mocked',
  219. timestamp: 1558038519831,
  220. uniqueLabels: {},
  221. },
  222. {
  223. entry: 'This is a previous message 2',
  224. fresh: true,
  225. hasAnsi: false,
  226. labels: { cluster: 'some-cluster' },
  227. logLevel: 'unknown',
  228. raw: 'This is a previous message 2',
  229. searchWords: [] as string[],
  230. timeEpochMs: 1558038518831,
  231. timeFromNow: 'fromNow() jest mocked',
  232. timeLocal: 'format() jest mocked',
  233. timeUtc: 'format() jest mocked',
  234. timestamp: 1558038518831,
  235. uniqueLabels: {},
  236. },
  237. ],
  238. series: [
  239. {
  240. label: 'A-series',
  241. color: '#7EB26D',
  242. data: [[1558038518831, 37.91264531864214], [1558038519831, 38.35179822906545]],
  243. info: undefined,
  244. isVisible: true,
  245. yAxis: {
  246. index: 1,
  247. },
  248. },
  249. ],
  250. },
  251. });
  252. const theResult = resultProcessor.getLogsResult();
  253. const expected = {
  254. hasUniqueLabels: false,
  255. meta: [] as LogsMetaItem[],
  256. rows: [
  257. {
  258. entry: 'This is a previous message 1',
  259. fresh: false,
  260. hasAnsi: false,
  261. labels: { cluster: 'some-cluster' },
  262. logLevel: 'unknown',
  263. raw: 'This is a previous message 1',
  264. searchWords: [] as string[],
  265. timeEpochMs: 1558038519831,
  266. timeFromNow: 'fromNow() jest mocked',
  267. timeLocal: 'format() jest mocked',
  268. timeUtc: 'format() jest mocked',
  269. timestamp: 1558038519831,
  270. uniqueLabels: {},
  271. },
  272. {
  273. entry: 'This is a previous message 2',
  274. fresh: false,
  275. hasAnsi: false,
  276. labels: { cluster: 'some-cluster' },
  277. logLevel: 'unknown',
  278. raw: 'This is a previous message 2',
  279. searchWords: [] as string[],
  280. timeEpochMs: 1558038518831,
  281. timeFromNow: 'fromNow() jest mocked',
  282. timeLocal: 'format() jest mocked',
  283. timeUtc: 'format() jest mocked',
  284. timestamp: 1558038518831,
  285. uniqueLabels: {},
  286. },
  287. {
  288. entry: 'third',
  289. fresh: true,
  290. hasAnsi: false,
  291. labels: undefined,
  292. logLevel: 'unknown',
  293. raw: 'third',
  294. searchWords: [] as string[],
  295. timeEpochMs: 300,
  296. timeFromNow: 'fromNow() jest mocked',
  297. timeLocal: 'format() jest mocked',
  298. timeUtc: 'format() jest mocked',
  299. timestamp: 300,
  300. uniqueLabels: {},
  301. },
  302. {
  303. entry: 'second message',
  304. fresh: true,
  305. hasAnsi: false,
  306. labels: undefined,
  307. logLevel: 'unknown',
  308. raw: 'second message',
  309. searchWords: [] as string[],
  310. timeEpochMs: 200,
  311. timeFromNow: 'fromNow() jest mocked',
  312. timeLocal: 'format() jest mocked',
  313. timeUtc: 'format() jest mocked',
  314. timestamp: 200,
  315. uniqueLabels: {},
  316. },
  317. {
  318. entry: 'this is a message',
  319. fresh: true,
  320. hasAnsi: false,
  321. labels: undefined,
  322. logLevel: 'unknown',
  323. raw: 'this is a message',
  324. searchWords: [] as string[],
  325. timeEpochMs: 100,
  326. timeFromNow: 'fromNow() jest mocked',
  327. timeLocal: 'format() jest mocked',
  328. timeUtc: 'format() jest mocked',
  329. timestamp: 100,
  330. uniqueLabels: {},
  331. },
  332. ],
  333. series: [
  334. {
  335. label: 'A-series',
  336. color: '#7EB26D',
  337. data: [[100, 4], [200, 5], [300, 6]],
  338. info: undefined,
  339. isVisible: true,
  340. yAxis: {
  341. index: 1,
  342. },
  343. } as GraphSeriesXY,
  344. ],
  345. };
  346. expect(theResult).toEqual(expected);
  347. });
  348. });
  349. });
  350. });