language_provider.test.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import Plain from 'slate-plain-serializer';
  2. import LanguageProvider, { LABEL_REFRESH_INTERVAL } from './language_provider';
  3. import { advanceTo, clear, advanceBy } from 'jest-date-mock';
  4. import { beforeEach } from 'test/lib/common';
  5. describe('Language completion provider', () => {
  6. const datasource = {
  7. metadataRequest: () => ({ data: { data: [] } }),
  8. };
  9. describe('empty query suggestions', () => {
  10. it('returns no suggestions on emtpty context', () => {
  11. const instance = new LanguageProvider(datasource);
  12. const value = Plain.deserialize('');
  13. const result = instance.provideCompletionItems({ text: '', prefix: '', value, wrapperClasses: [] });
  14. expect(result.context).toBeUndefined();
  15. expect(result.refresher).toBeUndefined();
  16. expect(result.suggestions.length).toEqual(0);
  17. });
  18. it('returns default suggestions with history on emtpty context when history was provided', () => {
  19. const instance = new LanguageProvider(datasource);
  20. const value = Plain.deserialize('');
  21. const history = [
  22. {
  23. query: { refId: '1', expr: '{app="foo"}' },
  24. },
  25. ];
  26. const result = instance.provideCompletionItems({ text: '', prefix: '', value, wrapperClasses: [] }, { history });
  27. expect(result.context).toBeUndefined();
  28. expect(result.refresher).toBeUndefined();
  29. expect(result.suggestions).toMatchObject([
  30. {
  31. label: 'History',
  32. items: [
  33. {
  34. label: '{app="foo"}',
  35. },
  36. ],
  37. },
  38. ]);
  39. });
  40. it('returns no suggestions within regexp', () => {
  41. const instance = new LanguageProvider(datasource);
  42. const value = Plain.deserialize('{} ()');
  43. const range = value.selection.merge({
  44. anchorOffset: 4,
  45. });
  46. const valueWithSelection = value.change().select(range).value;
  47. const history = [
  48. {
  49. query: { refId: '1', expr: '{app="foo"}' },
  50. },
  51. ];
  52. const result = instance.provideCompletionItems(
  53. {
  54. text: '',
  55. prefix: '',
  56. value: valueWithSelection,
  57. wrapperClasses: [],
  58. },
  59. { history }
  60. );
  61. expect(result.context).toBeUndefined();
  62. expect(result.refresher).toBeUndefined();
  63. expect(result.suggestions.length).toEqual(0);
  64. });
  65. });
  66. describe('label suggestions', () => {
  67. it('returns default label suggestions on label context', () => {
  68. const instance = new LanguageProvider(datasource);
  69. const value = Plain.deserialize('{}');
  70. const range = value.selection.merge({
  71. anchorOffset: 1,
  72. });
  73. const valueWithSelection = value.change().select(range).value;
  74. const result = instance.provideCompletionItems({
  75. text: '',
  76. prefix: '',
  77. wrapperClasses: ['context-labels'],
  78. value: valueWithSelection,
  79. });
  80. expect(result.context).toBe('context-labels');
  81. expect(result.suggestions).toEqual([{ items: [{ label: 'job' }, { label: 'namespace' }], label: 'Labels' }]);
  82. });
  83. });
  84. });
  85. describe('Query imports', () => {
  86. const datasource = {
  87. metadataRequest: () => ({ data: { data: [] } }),
  88. };
  89. it('returns empty queries for unknown origin datasource', async () => {
  90. const instance = new LanguageProvider(datasource);
  91. const result = await instance.importQueries([{ refId: 'bar', expr: 'foo' }], 'unknown');
  92. expect(result).toEqual([{ refId: 'bar', expr: '' }]);
  93. });
  94. describe('prometheus query imports', () => {
  95. it('returns empty query from metric-only query', async () => {
  96. const instance = new LanguageProvider(datasource);
  97. const result = await instance.importPrometheusQuery('foo');
  98. expect(result).toEqual('');
  99. });
  100. it('returns empty query from selector query if label is not available', async () => {
  101. const datasourceWithLabels = {
  102. metadataRequest: url => (url === '/api/prom/label' ? { data: { data: ['other'] } } : { data: { data: [] } }),
  103. };
  104. const instance = new LanguageProvider(datasourceWithLabels);
  105. const result = await instance.importPrometheusQuery('{foo="bar"}');
  106. expect(result).toEqual('{}');
  107. });
  108. it('returns selector query from selector query with common labels', async () => {
  109. const datasourceWithLabels = {
  110. metadataRequest: url => (url === '/api/prom/label' ? { data: { data: ['foo'] } } : { data: { data: [] } }),
  111. };
  112. const instance = new LanguageProvider(datasourceWithLabels);
  113. const result = await instance.importPrometheusQuery('metric{foo="bar",baz="42"}');
  114. expect(result).toEqual('{foo="bar"}');
  115. });
  116. it('returns selector query from selector query with all labels if logging label list is empty', async () => {
  117. const datasourceWithLabels = {
  118. metadataRequest: url => (url === '/api/prom/label' ? { data: { data: [] } } : { data: { data: [] } }),
  119. };
  120. const instance = new LanguageProvider(datasourceWithLabels);
  121. const result = await instance.importPrometheusQuery('metric{foo="bar",baz="42"}');
  122. expect(result).toEqual('{baz="42",foo="bar"}');
  123. });
  124. });
  125. });
  126. describe('Labels refresh', () => {
  127. const datasource = {
  128. metadataRequest: () => ({ data: { data: [] } }),
  129. };
  130. const instance = new LanguageProvider(datasource);
  131. beforeEach(() => {
  132. instance.fetchLogLabels = jest.fn();
  133. });
  134. afterEach(() => {
  135. jest.clearAllMocks();
  136. clear();
  137. });
  138. it("should not refresh labels if refresh interval hasn't passed", () => {
  139. advanceTo(new Date(2019, 1, 1, 0, 0, 0));
  140. instance.logLabelFetchTs = Date.now();
  141. advanceBy(LABEL_REFRESH_INTERVAL / 2);
  142. instance.refreshLogLabels();
  143. expect(instance.fetchLogLabels).not.toBeCalled();
  144. });
  145. it('should refresh labels if refresh interval passed', () => {
  146. advanceTo(new Date(2019, 1, 1, 0, 0, 0));
  147. instance.logLabelFetchTs = Date.now();
  148. advanceBy(LABEL_REFRESH_INTERVAL + 1);
  149. instance.refreshLogLabels();
  150. expect(instance.fetchLogLabels).toBeCalled();
  151. });
  152. });