graphTransform.test.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import { ArrayVector, DataFrameView, dateTime, MutableDataFrame } from '@grafana/data';
  2. import { createGraphFrames, mapPromMetricsToServiceMap } from './graphTransform';
  3. import { bigResponse } from './testResponse';
  4. describe('createGraphFrames', () => {
  5. it('transforms basic response into nodes and edges frame', async () => {
  6. const frames = createGraphFrames(bigResponse);
  7. expect(frames.length).toBe(2);
  8. expect(frames[0].length).toBe(30);
  9. expect(frames[1].length).toBe(29);
  10. let view = new DataFrameView(frames[0]);
  11. expect(view.get(0)).toMatchObject({
  12. id: '4322526419282105830',
  13. title: 'loki-all',
  14. subtitle: 'store.validateQueryTimeRange',
  15. mainstat: '0ms (0.02%)',
  16. secondarystat: '0ms (100%)',
  17. color: 0.00021968356127648162,
  18. });
  19. expect(view.get(29)).toMatchObject({
  20. id: '4450900759028499335',
  21. title: 'loki-all',
  22. subtitle: 'HTTP GET - loki_api_v1_query_range',
  23. mainstat: '18.21ms (100%)',
  24. secondarystat: '3.22ms (17.71%)',
  25. color: 0.17707117189595056,
  26. });
  27. view = new DataFrameView(frames[1]);
  28. expect(view.get(28)).toMatchObject({
  29. id: '4450900759028499335--4790760741274015949',
  30. });
  31. });
  32. it('handles single span response', async () => {
  33. const frames = createGraphFrames(singleSpanResponse);
  34. expect(frames.length).toBe(2);
  35. expect(frames[0].length).toBe(1);
  36. const view = new DataFrameView(frames[0]);
  37. expect(view.get(0)).toMatchObject({
  38. id: '4322526419282105830',
  39. title: 'loki-all',
  40. subtitle: 'store.validateQueryTimeRange',
  41. mainstat: '14.98ms (100%)',
  42. secondarystat: '14.98ms (100%)',
  43. color: 1.000007560204647,
  44. });
  45. });
  46. it('handles missing spans', async () => {
  47. const frames = createGraphFrames(missingSpanResponse);
  48. expect(frames.length).toBe(2);
  49. expect(frames[0].length).toBe(2);
  50. expect(frames[1].length).toBe(0);
  51. });
  52. });
  53. describe('mapPromMetricsToServiceMap', () => {
  54. it('transforms prom metrics to service graph', async () => {
  55. const range = {
  56. from: dateTime('2000-01-01T00:00:00'),
  57. to: dateTime('2000-01-01T00:01:00'),
  58. };
  59. const { nodes, edges } = mapPromMetricsToServiceMap(
  60. [{ data: [totalsPromMetric, secondsPromMetric, failedPromMetric] }],
  61. {
  62. ...range,
  63. raw: range,
  64. }
  65. );
  66. expect(nodes.fields).toMatchObject([
  67. { name: 'id', values: new ArrayVector(['db', 'app', 'lb']) },
  68. { name: 'title', values: new ArrayVector(['db', 'app', 'lb']) },
  69. { name: 'mainstat', values: new ArrayVector([1000, 2000, NaN]) },
  70. { name: 'secondarystat', values: new ArrayVector([0.17, 0.33, NaN]) },
  71. { name: 'arc__success', values: new ArrayVector([0.8, 0.25, 1]) },
  72. { name: 'arc__failed', values: new ArrayVector([0.2, 0.75, 0]) },
  73. ]);
  74. expect(edges.fields).toMatchObject([
  75. { name: 'id', values: new ArrayVector(['app_db', 'lb_app']) },
  76. { name: 'source', values: new ArrayVector(['app', 'lb']) },
  77. { name: 'target', values: new ArrayVector(['db', 'app']) },
  78. { name: 'mainstat', values: new ArrayVector([10, 20]) },
  79. { name: 'secondarystat', values: new ArrayVector([1000, 2000]) },
  80. ]);
  81. });
  82. it('handles invalid failed count', () => {
  83. // If node.failed > node.total, the stat circle will render in the wrong position
  84. // Fixed this by limiting the failed value to the total value
  85. const range = {
  86. from: dateTime('2000-01-01T00:00:00'),
  87. to: dateTime('2000-01-01T00:01:00'),
  88. };
  89. const { nodes } = mapPromMetricsToServiceMap(
  90. [{ data: [totalsPromMetric, secondsPromMetric, invalidFailedPromMetric] }],
  91. {
  92. ...range,
  93. raw: range,
  94. }
  95. );
  96. expect(nodes.fields).toMatchObject([
  97. { name: 'id', values: new ArrayVector(['db', 'app', 'lb']) },
  98. { name: 'title', values: new ArrayVector(['db', 'app', 'lb']) },
  99. { name: 'mainstat', values: new ArrayVector([1000, 2000, NaN]) },
  100. { name: 'secondarystat', values: new ArrayVector([0.17, 0.33, NaN]) },
  101. { name: 'arc__success', values: new ArrayVector([0, 0, 1]) },
  102. { name: 'arc__failed', values: new ArrayVector([1, 1, 0]) },
  103. ]);
  104. });
  105. });
  106. const singleSpanResponse = new MutableDataFrame({
  107. fields: [
  108. { name: 'traceID', values: ['04450900759028499335'] },
  109. { name: 'spanID', values: ['4322526419282105830'] },
  110. { name: 'parentSpanID', values: [''] },
  111. { name: 'operationName', values: ['store.validateQueryTimeRange'] },
  112. { name: 'serviceName', values: ['loki-all'] },
  113. { name: 'startTime', values: [1619712655875.4539] },
  114. { name: 'duration', values: [14.984] },
  115. ],
  116. });
  117. const missingSpanResponse = new MutableDataFrame({
  118. fields: [
  119. { name: 'traceID', values: ['04450900759028499335', '04450900759028499335'] },
  120. { name: 'spanID', values: ['1', '2'] },
  121. { name: 'parentSpanID', values: ['', '3'] },
  122. { name: 'operationName', values: ['store.validateQueryTimeRange', 'store.validateQueryTimeRange'] },
  123. { name: 'serviceName', values: ['loki-all', 'loki-all'] },
  124. { name: 'startTime', values: [1619712655875.4539, 1619712655880.4539] },
  125. { name: 'duration', values: [14.984, 4.984] },
  126. ],
  127. });
  128. const totalsPromMetric = new MutableDataFrame({
  129. refId: 'traces_service_graph_request_total',
  130. fields: [
  131. { name: 'Time', values: [1628169788000, 1628169788000] },
  132. { name: 'client', values: ['app', 'lb'] },
  133. { name: 'instance', values: ['127.0.0.1:12345', '127.0.0.1:12345'] },
  134. { name: 'job', values: ['local_scrape', 'local_scrape'] },
  135. { name: 'server', values: ['db', 'app'] },
  136. { name: 'tempo_config', values: ['default', 'default'] },
  137. { name: 'Value #traces_service_graph_request_total', values: [10, 20] },
  138. ],
  139. });
  140. const secondsPromMetric = new MutableDataFrame({
  141. refId: 'traces_service_graph_request_server_seconds_sum',
  142. fields: [
  143. { name: 'Time', values: [1628169788000, 1628169788000] },
  144. { name: 'client', values: ['app', 'lb'] },
  145. { name: 'instance', values: ['127.0.0.1:12345', '127.0.0.1:12345'] },
  146. { name: 'job', values: ['local_scrape', 'local_scrape'] },
  147. { name: 'server', values: ['db', 'app'] },
  148. { name: 'tempo_config', values: ['default', 'default'] },
  149. { name: 'Value #traces_service_graph_request_server_seconds_sum', values: [10, 40] },
  150. ],
  151. });
  152. const failedPromMetric = new MutableDataFrame({
  153. refId: 'traces_service_graph_request_failed_total',
  154. fields: [
  155. { name: 'Time', values: [1628169788000, 1628169788000] },
  156. { name: 'client', values: ['app', 'lb'] },
  157. { name: 'instance', values: ['127.0.0.1:12345', '127.0.0.1:12345'] },
  158. { name: 'job', values: ['local_scrape', 'local_scrape'] },
  159. { name: 'server', values: ['db', 'app'] },
  160. { name: 'tempo_config', values: ['default', 'default'] },
  161. { name: 'Value #traces_service_graph_request_failed_total', values: [2, 15] },
  162. ],
  163. });
  164. const invalidFailedPromMetric = new MutableDataFrame({
  165. refId: 'traces_service_graph_request_failed_total',
  166. fields: [
  167. { name: 'Time', values: [1628169788000, 1628169788000] },
  168. { name: 'client', values: ['app', 'lb'] },
  169. { name: 'instance', values: ['127.0.0.1:12345', '127.0.0.1:12345'] },
  170. { name: 'job', values: ['local_scrape', 'local_scrape'] },
  171. { name: 'server', values: ['db', 'app'] },
  172. { name: 'tempo_config', values: ['default', 'default'] },
  173. { name: 'Value #traces_service_graph_request_failed_total', values: [20, 40] },
  174. ],
  175. });