PanelQueryState.test.ts 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. import { toDataQueryError, PanelQueryState, getProcessedDataFrame } from './PanelQueryState';
  2. import { MockDataSourceApi } from 'test/mocks/datasource_srv';
  3. import { DataQueryResponse, LoadingState } from '@grafana/ui';
  4. import { getQueryOptions } from 'test/helpers/getQueryOptions';
  5. describe('PanelQueryState', () => {
  6. it('converts anythign to an error', () => {
  7. let err = toDataQueryError(undefined);
  8. expect(err.message).toEqual('Query error');
  9. err = toDataQueryError('STRING ERRROR');
  10. expect(err.message).toEqual('STRING ERRROR');
  11. err = toDataQueryError({ message: 'hello' });
  12. expect(err.message).toEqual('hello');
  13. });
  14. it('keeps track of running queries', async () => {
  15. const state = new PanelQueryState();
  16. expect(state.getActiveRunner()).toBeFalsy();
  17. let hasRun = false;
  18. const dsRunner = new Promise<DataQueryResponse>((resolve, reject) => {
  19. // The status should be running when we get here
  20. expect(state.getActiveRunner()).toBeTruthy();
  21. resolve({ data: ['x', 'y'] });
  22. hasRun = true;
  23. });
  24. const ds = new MockDataSourceApi('test');
  25. ds.queryResolver = dsRunner;
  26. // should not actually run for an empty query
  27. let empty = await state.execute(ds, getQueryOptions({}));
  28. expect(state.getActiveRunner()).toBeFalsy();
  29. expect(empty.series.length).toBe(0);
  30. expect(hasRun).toBeFalsy();
  31. const query = getQueryOptions({
  32. targets: [{ hide: true, refId: 'X' }, { hide: true, refId: 'Y' }, { hide: true, refId: 'Z' }],
  33. });
  34. empty = await state.execute(ds, query);
  35. // should not run any hidden queries'
  36. expect(state.getActiveRunner()).toBeFalsy();
  37. expect(empty.series.length).toBe(0);
  38. expect(hasRun).toBeFalsy();
  39. // Check for the same query
  40. expect(state.isSameQuery(ds, query)).toBeTruthy();
  41. // Check for differnet queries
  42. expect(state.isSameQuery(new MockDataSourceApi('test'), query)).toBeFalsy();
  43. expect(state.isSameQuery(ds, getQueryOptions({ targets: [{ refId: 'differnet' }] }))).toBeFalsy();
  44. });
  45. });
  46. describe('getProcessedDataFrame', () => {
  47. it('converts timeseries to table skipping nulls', () => {
  48. const input1 = {
  49. target: 'Field Name',
  50. datapoints: [[100, 1], [200, 2]],
  51. };
  52. const input2 = {
  53. // without target
  54. target: '',
  55. datapoints: [[100, 1], [200, 2]],
  56. };
  57. const data = getProcessedDataFrame([null, input1, input2, null, null]);
  58. expect(data.length).toBe(2);
  59. expect(data[0].fields[0].name).toBe(input1.target);
  60. expect(data[0].rows).toBe(input1.datapoints);
  61. // Default name
  62. expect(data[1].fields[0].name).toEqual('Value');
  63. // Every colun should have a name and a type
  64. for (const table of data) {
  65. for (const column of table.fields) {
  66. expect(column.name).toBeDefined();
  67. expect(column.type).toBeDefined();
  68. }
  69. }
  70. });
  71. it('supports null values from query OK', () => {
  72. expect(getProcessedDataFrame([null, null, null, null])).toEqual([]);
  73. expect(getProcessedDataFrame(undefined)).toEqual([]);
  74. expect(getProcessedDataFrame((null as unknown) as any[])).toEqual([]);
  75. expect(getProcessedDataFrame([])).toEqual([]);
  76. });
  77. });
  78. function makeSeriesStub(refId: string) {
  79. return {
  80. fields: [{ name: 'a' }],
  81. rows: [],
  82. refId,
  83. };
  84. }
  85. describe('stream handling', () => {
  86. const state = new PanelQueryState();
  87. state.onStreamingDataUpdated = () => {
  88. // nothing
  89. };
  90. state.request = {
  91. requestId: '123',
  92. range: {
  93. raw: {
  94. from: 123, // if string it gets revaluated
  95. },
  96. },
  97. } as any;
  98. state.response = {
  99. state: LoadingState.Done,
  100. series: [makeSeriesStub('A'), makeSeriesStub('B')],
  101. };
  102. it('gets the response', () => {
  103. const data = state.validateStreamsAndGetPanelData();
  104. expect(data.series.length).toBe(2);
  105. expect(data.state).toBe(LoadingState.Done);
  106. expect(data.series[0].refId).toBe('A');
  107. });
  108. it('adds a stream event', () => {
  109. // Post a stream event
  110. state.dataStreamObserver({
  111. state: LoadingState.Loading,
  112. key: 'C',
  113. request: state.request, // From the same request
  114. series: [makeSeriesStub('C')],
  115. unsubscribe: () => {},
  116. });
  117. expect(state.streams.length).toBe(1);
  118. const data = state.validateStreamsAndGetPanelData();
  119. expect(data.series.length).toBe(3);
  120. expect(data.state).toBe(LoadingState.Streaming);
  121. expect(data.series[2].refId).toBe('C');
  122. });
  123. it('add another stream event (with a differnet key)', () => {
  124. // Post a stream event
  125. state.dataStreamObserver({
  126. state: LoadingState.Loading,
  127. key: 'D',
  128. request: state.request, // From the same request
  129. series: [makeSeriesStub('D')],
  130. unsubscribe: () => {},
  131. });
  132. expect(state.streams.length).toBe(2);
  133. const data = state.validateStreamsAndGetPanelData();
  134. expect(data.series.length).toBe(4);
  135. expect(data.state).toBe(LoadingState.Streaming);
  136. expect(data.series[3].refId).toBe('D');
  137. });
  138. it('replace the first stream value, but keep the order', () => {
  139. // Post a stream event
  140. state.dataStreamObserver({
  141. state: LoadingState.Loading,
  142. key: 'C', // The key to replace previous index 2
  143. request: state.request, // From the same request
  144. series: [makeSeriesStub('X')],
  145. unsubscribe: () => {},
  146. });
  147. expect(state.streams.length).toBe(2);
  148. const data = state.validateStreamsAndGetPanelData();
  149. expect(data.series[2].refId).toBe('X');
  150. });
  151. it('ignores streams from a differnet request', () => {
  152. // Post a stream event
  153. state.dataStreamObserver({
  154. state: LoadingState.Loading,
  155. key: 'Z', // Note with key 'A' it would still overwrite
  156. request: {
  157. ...state.request,
  158. requestId: 'XXX', // Different request and id
  159. } as any,
  160. series: [makeSeriesStub('C')],
  161. unsubscribe: () => {},
  162. });
  163. expect(state.streams.length).toBe(2); // no change
  164. const data = state.validateStreamsAndGetPanelData();
  165. expect(data.series.length).toBe(4);
  166. });
  167. it('removes streams when the query changes', () => {
  168. state.request = {
  169. ...state.request,
  170. requestId: 'somethine else',
  171. } as any;
  172. state.response = {
  173. state: LoadingState.Done,
  174. series: [makeSeriesStub('F')],
  175. };
  176. expect(state.streams.length).toBe(2); // unchanged
  177. const data = state.validateStreamsAndGetPanelData();
  178. expect(data.series.length).toBe(1);
  179. expect(data.series[0].refId).toBe('F');
  180. expect(state.streams.length).toBe(0); // no streams
  181. });
  182. });