query_hints.test.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import { PrometheusDatasource } from './datasource';
  2. import { getQueryHints, SUM_HINT_THRESHOLD_COUNT } from './query_hints';
  3. describe('getQueryHints()', () => {
  4. it('returns no hints for no series', () => {
  5. expect(getQueryHints('', [])).toEqual([]);
  6. });
  7. it('returns no hints for empty series', () => {
  8. expect(getQueryHints('', [{ datapoints: [] }])).toEqual([]);
  9. });
  10. it('returns a rate hint for a counter metric', () => {
  11. const series = [
  12. {
  13. datapoints: [
  14. [23, 1000],
  15. [24, 1001],
  16. ],
  17. },
  18. ];
  19. const hints = getQueryHints('metric_total', series);
  20. expect(hints!.length).toBe(1);
  21. expect(hints![0]).toMatchObject({
  22. label: 'Selected metric looks like a counter.',
  23. fix: {
  24. action: {
  25. type: 'ADD_RATE',
  26. query: 'metric_total',
  27. },
  28. },
  29. });
  30. });
  31. it('returns a certain rate hint for a counter metric', () => {
  32. const series = [
  33. {
  34. datapoints: [
  35. [23, 1000],
  36. [24, 1001],
  37. ],
  38. },
  39. ];
  40. const mock: unknown = { languageProvider: { metricsMetadata: { foo: { type: 'counter' } } } };
  41. const datasource = mock as PrometheusDatasource;
  42. let hints = getQueryHints('foo', series, datasource);
  43. expect(hints!.length).toBe(1);
  44. expect(hints![0]).toMatchObject({
  45. label: 'Selected metric is a counter.',
  46. fix: {
  47. action: {
  48. type: 'ADD_RATE',
  49. query: 'foo',
  50. },
  51. },
  52. });
  53. // Test substring match not triggering hint
  54. hints = getQueryHints('foo_foo', series, datasource);
  55. expect(hints).toEqual([]);
  56. });
  57. it('returns no rate hint for a counter metric that already has a rate', () => {
  58. const series = [
  59. {
  60. datapoints: [
  61. [23, 1000],
  62. [24, 1001],
  63. ],
  64. },
  65. ];
  66. const hints = getQueryHints('rate(metric_total[1m])', series);
  67. expect(hints).toEqual([]);
  68. });
  69. it('returns no rate hint for a counter metric that already has an increase', () => {
  70. const series = [
  71. {
  72. datapoints: [
  73. [23, 1000],
  74. [24, 1001],
  75. ],
  76. },
  77. ];
  78. const hints = getQueryHints('increase(metric_total[1m])', series);
  79. expect(hints).toEqual([]);
  80. });
  81. it('returns a rate hint with action for a counter metric with labels', () => {
  82. const series = [
  83. {
  84. datapoints: [
  85. [23, 1000],
  86. [24, 1001],
  87. ],
  88. },
  89. ];
  90. const hints = getQueryHints('metric_total{job="grafana"}', series);
  91. expect(hints!.length).toBe(1);
  92. expect(hints![0].label).toContain('Selected metric looks like a counter');
  93. expect(hints![0].fix).toBeDefined();
  94. });
  95. it('returns a rate hint w/o action for a complex counter metric', () => {
  96. const series = [
  97. {
  98. datapoints: [
  99. [23, 1000],
  100. [24, 1001],
  101. ],
  102. },
  103. ];
  104. const hints = getQueryHints('sum(metric_total)', series);
  105. expect(hints!.length).toBe(1);
  106. expect(hints![0].label).toContain('rate()');
  107. expect(hints![0].fix).toBeUndefined();
  108. });
  109. it('returns a histogram hint for a bucket series', () => {
  110. const series = [{ datapoints: [[23, 1000]] }];
  111. const hints = getQueryHints('metric_bucket', series);
  112. expect(hints!.length).toBe(1);
  113. expect(hints![0]).toMatchObject({
  114. label: 'Selected metric has buckets.',
  115. fix: {
  116. action: {
  117. type: 'ADD_HISTOGRAM_QUANTILE',
  118. query: 'metric_bucket',
  119. },
  120. },
  121. });
  122. });
  123. it('returns a histogram hint with action for a bucket with labels', () => {
  124. const series = [
  125. {
  126. datapoints: [
  127. [23, 1000],
  128. [24, 1001],
  129. ],
  130. },
  131. ];
  132. const hints = getQueryHints('metric_bucket{job="grafana"}', series);
  133. expect(hints!.length).toBe(1);
  134. expect(hints![0].label).toContain('Selected metric has buckets.');
  135. expect(hints![0].fix).toBeDefined();
  136. });
  137. it('returns a sum hint when many time series results are returned for a simple metric', () => {
  138. const seriesCount = SUM_HINT_THRESHOLD_COUNT;
  139. const series = Array.from({ length: seriesCount }, (_) => ({
  140. datapoints: [
  141. [0, 0],
  142. [0, 0],
  143. ],
  144. }));
  145. const hints = getQueryHints('metric', series);
  146. expect(hints!.length).toBe(1);
  147. expect(hints![0]).toMatchObject({
  148. type: 'ADD_SUM',
  149. label: 'Many time series results returned.',
  150. fix: {
  151. label: 'Consider aggregating with sum().',
  152. action: {
  153. type: 'ADD_SUM',
  154. query: 'metric',
  155. preventSubmit: true,
  156. },
  157. },
  158. });
  159. });
  160. });