search-utils-test.js 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. import { fromJS } from 'immutable';
  2. const SearchUtils = require('../search-utils').testable;
  3. describe('SearchUtils', () => {
  4. const nodeSets = {
  5. someNodes: fromJS({
  6. n1: {
  7. id: 'n1',
  8. label: 'node label 1',
  9. metadata: [{
  10. id: 'fieldId1',
  11. label: 'Label 1',
  12. value: 'value 1'
  13. }],
  14. metrics: [{
  15. id: 'metric1',
  16. label: 'Metric 1',
  17. value: 1
  18. }]
  19. },
  20. n2: {
  21. id: 'n2',
  22. label: 'node label 2',
  23. metadata: [{
  24. id: 'fieldId2',
  25. label: 'Label 2',
  26. value: 'value 2'
  27. }],
  28. tables: [{
  29. id: 'metric1',
  30. rows: [{
  31. entries: {
  32. label: 'Label 1',
  33. value: 'Label Value 1'
  34. },
  35. id: 'label1'
  36. }, {
  37. entries: {
  38. label: 'Label 2',
  39. value: 'Label Value 2'
  40. },
  41. id: 'label2'
  42. }],
  43. type: 'property-list'
  44. }, {
  45. columns: [{
  46. id: 'a',
  47. label: 'A'
  48. }, {
  49. id: 'c',
  50. label: 'C'
  51. }],
  52. id: 'metric2',
  53. rows: [{
  54. entries: {
  55. a: 'xxxa',
  56. b: 'yyya',
  57. c: 'zzz1'
  58. },
  59. id: 'row1'
  60. }, {
  61. entries: {
  62. a: 'yyyb',
  63. b: 'xxxb',
  64. c: 'zzz2'
  65. },
  66. id: 'row2'
  67. }, {
  68. entries: {
  69. a: 'Value 1',
  70. b: 'Value 2',
  71. c: 'Value 3'
  72. },
  73. id: 'row3'
  74. }],
  75. type: 'multicolumn-table'
  76. }],
  77. },
  78. })
  79. };
  80. describe('applyPinnedSearches', () => {
  81. const fun = SearchUtils.applyPinnedSearches;
  82. it('should not filter anything when no pinned searches present', () => {
  83. let nextState = fromJS({
  84. nodes: nodeSets.someNodes,
  85. pinnedSearches: []
  86. });
  87. nextState = fun(nextState);
  88. expect(nextState.get('nodes').filter(node => node.get('filtered')).size).toEqual(0);
  89. });
  90. it('should filter nodes if nothing matches a pinned search', () => {
  91. let nextState = fromJS({
  92. nodes: nodeSets.someNodes,
  93. pinnedSearches: ['cantmatch']
  94. });
  95. nextState = fun(nextState);
  96. expect(nextState.get('nodes').filterNot(node => node.get('filtered')).size).toEqual(0);
  97. });
  98. it('should filter nodes if nothing matches a combination of pinned searches', () => {
  99. let nextState = fromJS({
  100. nodes: nodeSets.someNodes,
  101. pinnedSearches: ['node label 1', 'node label 2']
  102. });
  103. nextState = fun(nextState);
  104. expect(nextState.get('nodes').filterNot(node => node.get('filtered')).size).toEqual(0);
  105. });
  106. it('should filter nodes that do not match a pinned searches', () => {
  107. let nextState = fromJS({
  108. nodes: nodeSets.someNodes,
  109. pinnedSearches: ['Label Value 1']
  110. });
  111. nextState = fun(nextState);
  112. expect(nextState.get('nodes').filter(node => node.get('filtered')).size).toEqual(1);
  113. });
  114. });
  115. describe('findNodeMatch', () => {
  116. const fun = SearchUtils.findNodeMatch;
  117. it('does not add a non-matching field', () => {
  118. let matches = fromJS({});
  119. matches = fun(
  120. matches, ['node1', 'field1'],
  121. 'some value', 'some query', null, 'some label'
  122. );
  123. expect(matches.size).toBe(0);
  124. });
  125. it('adds a matching field', () => {
  126. let matches = fromJS({});
  127. matches = fun(
  128. matches, ['node1', 'field1'],
  129. 'samevalue', 'samevalue', null, 'some label'
  130. );
  131. expect(matches.size).toBe(1);
  132. expect(matches.getIn(['node1', 'field1'])).toBeDefined();
  133. const {
  134. text, label, start, length
  135. } = matches.getIn(['node1', 'field1']);
  136. expect(text).toBe('samevalue');
  137. expect(label).toBe('some label');
  138. expect(start).toBe(0);
  139. expect(length).toBe(9);
  140. });
  141. it('does not add a field when the prefix does not match the label', () => {
  142. let matches = fromJS({});
  143. matches = fun(
  144. matches, ['node1', 'field1'],
  145. 'samevalue', 'samevalue', 'some prefix', 'some label'
  146. );
  147. expect(matches.size).toBe(0);
  148. });
  149. it('adds a field when the prefix matches the label', () => {
  150. let matches = fromJS({});
  151. matches = fun(
  152. matches, ['node1', 'field1'],
  153. 'samevalue', 'samevalue', 'prefix', 'prefixed label'
  154. );
  155. expect(matches.size).toBe(1);
  156. });
  157. });
  158. describe('findNodeMatchMetric', () => {
  159. const fun = SearchUtils.findNodeMatchMetric;
  160. it('does not add a non-matching field', () => {
  161. let matches = fromJS({});
  162. matches = fun(
  163. matches, ['node1', 'field1'],
  164. 1, 'metric1', 'metric2', 'lt', 2
  165. );
  166. expect(matches.size).toBe(0);
  167. });
  168. it('adds a matching field', () => {
  169. let matches = fromJS({});
  170. matches = fun(
  171. matches, ['node1', 'field1'],
  172. 1, 'metric1', 'metric1', 'lt', 2
  173. );
  174. expect(matches.size).toBe(1);
  175. expect(matches.getIn(['node1', 'field1'])).toBeDefined();
  176. const { metric } = matches.getIn(['node1', 'field1']);
  177. expect(metric).toBeTruthy();
  178. matches = fun(
  179. matches, ['node2', 'field1'],
  180. 1, 'metric1', 'metric1', 'gt', 0
  181. );
  182. expect(matches.size).toBe(2);
  183. matches = fun(
  184. matches, ['node3', 'field1'],
  185. 1, 'metric1', 'metric1', 'eq', 1
  186. );
  187. expect(matches.size).toBe(3);
  188. matches = fun(
  189. matches, ['node3', 'field1'],
  190. 1, 'metric1', 'metric1', 'other', 1
  191. );
  192. expect(matches.size).toBe(3);
  193. });
  194. });
  195. describe('makeRegExp', () => {
  196. const fun = SearchUtils.makeRegExp;
  197. it('should make a regexp from any string', () => {
  198. expect(fun().source).toEqual((new RegExp()).source);
  199. expect(fun('que').source).toEqual((new RegExp('que')).source);
  200. // invalid string
  201. expect(fun('que[').source).toEqual((new RegExp('que\\[')).source);
  202. });
  203. });
  204. describe('matchPrefix', () => {
  205. const fun = SearchUtils.matchPrefix;
  206. it('returns true if the prefix matches the label', () => {
  207. expect(fun('label', 'prefix')).toBeFalsy();
  208. expect(fun('memory', 'mem')).toBeTruthy();
  209. expect(fun('mem', 'memory')).toBeFalsy();
  210. expect(fun('com.domain.label', 'label')).toBeTruthy();
  211. expect(fun('com.domain.Label', 'domainlabel')).toBeTruthy();
  212. expect(fun('com-Domain-label', 'domainlabel')).toBeTruthy();
  213. expect(fun('memory', 'mem.ry')).toBeTruthy();
  214. });
  215. });
  216. describe('parseQuery', () => {
  217. const fun = SearchUtils.parseQuery;
  218. it('should parse a metric value from a string', () => {
  219. expect(fun('')).toEqual(null);
  220. expect(fun('text')).toEqual({query: 'text'});
  221. expect(fun('prefix:text')).toEqual({prefix: 'prefix', query: 'text'});
  222. expect(fun(':text')).toEqual(null);
  223. expect(fun('text:')).toEqual(null);
  224. expect(fun('cpu > 1')).toEqual({comp: 'gt', metric: 'cpu', value: 1});
  225. expect(fun('cpu >')).toEqual(null);
  226. });
  227. });
  228. describe('parseValue', () => {
  229. const fun = SearchUtils.parseValue;
  230. it('should parse a metric value from a string', () => {
  231. expect(fun('1')).toEqual(1);
  232. expect(fun('1.34%')).toEqual(1.34);
  233. expect(fun('10kB')).toEqual(1024 * 10);
  234. expect(fun('1K')).toEqual(1024);
  235. expect(fun('2KB')).toEqual(2048);
  236. expect(fun('1MB')).toEqual(Math.pow(1024, 2));
  237. expect(fun('1m')).toEqual(Math.pow(1024, 2));
  238. expect(fun('1GB')).toEqual(Math.pow(1024, 3));
  239. expect(fun('1TB')).toEqual(Math.pow(1024, 4));
  240. });
  241. });
  242. describe('searchTopology', () => {
  243. const fun = SearchUtils.searchTopology;
  244. it('should return no matches on an empty topology', () => {
  245. const nodes = fromJS({});
  246. const matches = fun(nodes, {query: 'value'});
  247. expect(matches.size).toEqual(0);
  248. });
  249. it('should match on a node label', () => {
  250. const nodes = nodeSets.someNodes;
  251. let matches = fun(nodes, {query: 'node label 1'});
  252. expect(matches.size).toEqual(1);
  253. matches = fun(nodes, {query: 'node label'});
  254. expect(matches.size).toEqual(2);
  255. });
  256. it('should match on a metadata field', () => {
  257. const nodes = nodeSets.someNodes;
  258. const matches = fun(nodes, {query: 'value'});
  259. expect(matches.size).toEqual(2);
  260. expect(matches.getIn(['n1', 'metadata', 'fieldId1']).text).toEqual('value 1');
  261. });
  262. it('should match on a metric field', () => {
  263. const nodes = nodeSets.someNodes;
  264. const matches = fun(nodes, {comp: 'eq', metric: 'metric1', value: 1});
  265. expect(matches.size).toEqual(1);
  266. expect(matches.getIn(['n1', 'metrics', 'metric1']).metric).toBeTruthy();
  267. });
  268. it('should match on a property list value', () => {
  269. const nodes = nodeSets.someNodes;
  270. const matches = fun(nodes, {query: 'Value 1'});
  271. expect(matches.size).toEqual(2);
  272. expect(matches.getIn(['n2', 'property-lists']).size).toEqual(1);
  273. expect(matches.getIn(['n2', 'property-lists', 'label1']).text).toBe('Label Value 1');
  274. });
  275. it('should match on a generic table values', () => {
  276. const nodes = nodeSets.someNodes;
  277. const matches1 = fun(nodes, {query: 'xx'}).getIn(['n2', 'tables']);
  278. const matches2 = fun(nodes, {query: 'yy'}).getIn(['n2', 'tables']);
  279. const matches3 = fun(nodes, {query: 'zz'}).getIn(['n2', 'tables']);
  280. const matches4 = fun(nodes, {query: 'a'}).getIn(['n2', 'tables']);
  281. expect(matches1.size).toEqual(1);
  282. expect(matches2.size).toEqual(1);
  283. expect(matches3.size).toEqual(2);
  284. expect(matches4.size).toEqual(3);
  285. expect(matches1.get('row1_a').text).toBe('xxxa');
  286. expect(matches2.get('row2_a').text).toBe('yyyb');
  287. expect(matches3.get('row1_c').text).toBe('zzz1');
  288. expect(matches3.get('row2_c').text).toBe('zzz2');
  289. expect(matches4.get('row1_a').text).toBe('xxxa');
  290. expect(matches4.get('row3_a').text).toBe('Value 1');
  291. expect(matches4.get('row3_c').text).toBe('Value 3');
  292. });
  293. });
  294. });