utils.spec.tsx 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. import {
  2. getCurlCommand,
  3. getCurrentThread,
  4. getThreadById,
  5. objectToSortedTupleArray,
  6. removeFilterMaskedEntries,
  7. stringifyQueryList,
  8. } from 'sentry/components/events/interfaces/utils';
  9. import {MetaProxy, withMeta} from 'sentry/components/events/meta/metaProxy';
  10. import {FILTER_MASK} from 'sentry/constants';
  11. import {EntryType} from 'sentry/types/event';
  12. describe('components/interfaces/utils', function () {
  13. describe('getCurlCommand()', function () {
  14. it('should convert an http request object to an equivalent unix curl command string', function () {
  15. expect(
  16. getCurlCommand({
  17. apiTarget: null,
  18. cookies: [
  19. ['foo', 'bar'],
  20. ['biz', 'baz'],
  21. ],
  22. url: 'http://example.com/foo',
  23. headers: [
  24. ['Referer', 'http://example.com'],
  25. [
  26. 'User-Agent',
  27. 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36',
  28. ],
  29. ['Content-Type', 'application/json'],
  30. ],
  31. env: {
  32. ENV: 'prod',
  33. },
  34. fragment: '',
  35. query: [['foo', 'bar']],
  36. data: '{"hello": "world"}',
  37. method: 'GET',
  38. })
  39. ).toEqual(
  40. 'curl \\\n' +
  41. ' -H "Content-Type: application/json" \\\n' +
  42. ' -H "Referer: http://example.com" \\\n' +
  43. ' -H "User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36" \\\n' +
  44. ' --data "{\\"hello\\": \\"world\\"}" \\\n' +
  45. ' "http://example.com/foo?foo=bar"'
  46. );
  47. // --compressed (because Accept-Encoding: gzip)
  48. expect(
  49. getCurlCommand({
  50. apiTarget: null,
  51. url: 'http://example.com/foo',
  52. headers: [
  53. ['Content-Type', 'application/json'],
  54. ['Referer', 'http://example.com'],
  55. ['Accept-Encoding', 'gzip'],
  56. ],
  57. env: {
  58. ENV: 'prod',
  59. },
  60. fragment: '',
  61. query: [['foo', 'bar']],
  62. data: '{"hello": "world"}',
  63. method: 'GET',
  64. })
  65. ).toEqual(
  66. 'curl \\\n' +
  67. ' --compressed \\\n' +
  68. ' -H "Accept-Encoding: gzip" \\\n' +
  69. ' -H "Content-Type: application/json" \\\n' +
  70. ' -H "Referer: http://example.com" \\\n' +
  71. ' --data "{\\"hello\\": \\"world\\"}" \\\n' +
  72. ' "http://example.com/foo?foo=bar"'
  73. );
  74. // Do not add data if data is empty
  75. expect(
  76. getCurlCommand({
  77. apiTarget: null,
  78. url: 'http://example.com/foo',
  79. headers: [],
  80. env: {
  81. ENV: 'prod',
  82. },
  83. fragment: '',
  84. query: [['foo', 'bar']],
  85. method: 'GET',
  86. })
  87. ).toEqual('curl \\\n "http://example.com/foo?foo=bar"');
  88. // Do not add data if data is empty object
  89. expect(
  90. getCurlCommand({
  91. apiTarget: null,
  92. url: 'http://example.com/foo',
  93. headers: [],
  94. env: {
  95. ENV: 'prod',
  96. },
  97. inferredContentType: null,
  98. fragment: '',
  99. data: {},
  100. method: 'GET',
  101. })
  102. ).toEqual('curl \\\n "http://example.com/foo"');
  103. // Escape escaped strings.
  104. expect(
  105. getCurlCommand({
  106. apiTarget: null,
  107. cookies: [
  108. ['foo', 'bar'],
  109. ['biz', 'baz'],
  110. ],
  111. url: 'http://example.com/foo',
  112. headers: [
  113. ['Referer', 'http://example.com'],
  114. [
  115. 'User-Agent',
  116. 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36',
  117. ],
  118. ['Content-Type', 'application/json'],
  119. ],
  120. env: {
  121. ENV: 'prod',
  122. },
  123. fragment: '',
  124. query: [],
  125. data: '{"a":"b\\"c"}',
  126. method: 'GET',
  127. })
  128. ).toEqual(
  129. 'curl \\\n' +
  130. ' -H "Content-Type: application/json" \\\n' +
  131. ' -H "Referer: http://example.com" \\\n' +
  132. ' -H "User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36" \\\n' +
  133. ' --data "{\\"a\\":\\"b\\\\\\"c\\"}" \\\n' +
  134. ' "http://example.com/foo"'
  135. );
  136. // Escape strings with special bash characters
  137. expect(
  138. getCurlCommand({
  139. apiTarget: null,
  140. url: 'http://example.com/foo${not_a_variable}',
  141. headers: [
  142. ['Referer', 'http://example.com'],
  143. [
  144. 'User-Agent',
  145. 'Mozilla/5.0 ("Windows" NT 6.2; WOW64) $not_a_variable `test`',
  146. ],
  147. ['Content-Type', 'application/json'],
  148. ],
  149. fragment: '',
  150. query: [],
  151. data: '{"a$TEST":"b\\"c"}',
  152. method: 'GET',
  153. })
  154. ).toEqual(
  155. 'curl \\\n' +
  156. ' -H "Content-Type: application/json" \\\n' +
  157. ' -H "Referer: http://example.com" \\\n' +
  158. ' -H "User-Agent: Mozilla/5.0 (\\"Windows\\" NT 6.2; WOW64) \\$not_a_variable \\`test\\`" \\\n' +
  159. ' --data "{\\"a\\$TEST\\":\\"b\\\\\\"c\\"}" \\\n' +
  160. ' "http://example.com/foo\\${not_a_variable}"'
  161. );
  162. });
  163. it('works with a Proxy', function () {
  164. const spy = jest.spyOn(MetaProxy.prototype, 'get');
  165. const data = {
  166. apiTarget: null,
  167. fragment: '',
  168. cookies: [],
  169. inferredContentType: null,
  170. env: {
  171. SERVER_NAME: 'sentry',
  172. SERVER_PORT: '443',
  173. REMOTE_ADDR: '127.0.0.1',
  174. },
  175. headers: [
  176. ['Accept-Language', 'en'],
  177. ['Referer', 'http://example.com'],
  178. [
  179. 'User-Agent',
  180. 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36',
  181. ],
  182. ['Content-Type', 'application/json'],
  183. ['Referer', 'http://example.com'],
  184. ['Accept-Encoding', 'gzip'],
  185. ] as [string, string][],
  186. url: 'https://www.sentry.io',
  187. query: [],
  188. data: null,
  189. method: 'GET',
  190. };
  191. const eventWithProxy = withMeta(data);
  192. getCurlCommand(eventWithProxy);
  193. // This may need to change, but we should aim to keep this low
  194. expect(spy.mock.calls.length).toBeLessThan(200);
  195. });
  196. });
  197. describe('objectToSortedTupleArray()', function () {
  198. it('should convert a key/value object to a sorted array of key/value tuples', function () {
  199. expect(
  200. objectToSortedTupleArray({
  201. foo: ['bar', 'baz'],
  202. })
  203. ).toEqual([
  204. ['foo', 'bar'],
  205. ['foo', 'baz'],
  206. ]);
  207. });
  208. });
  209. describe('removeFilterMaskedEntries()', function () {
  210. const rawData = {
  211. id: '26',
  212. name: FILTER_MASK,
  213. username: 'maiseythedog',
  214. email: FILTER_MASK,
  215. };
  216. it('should remove filtered values', function () {
  217. const result = removeFilterMaskedEntries(rawData);
  218. expect(result).not.toHaveProperty('name');
  219. expect(result).not.toHaveProperty('email');
  220. });
  221. it('should preserve unfiltered values', function () {
  222. const result = removeFilterMaskedEntries(rawData);
  223. expect(result).toHaveProperty('id');
  224. expect(result.id).toEqual('26');
  225. expect(result).toHaveProperty('username');
  226. expect(result.username).toEqual('maiseythedog');
  227. });
  228. });
  229. describe('stringifyQueryList()', function () {
  230. it('should return query if it is a string', function () {
  231. const query = stringifyQueryList('query');
  232. expect(query).toEqual('query');
  233. });
  234. it('should parse query tuples', function () {
  235. const query = stringifyQueryList([
  236. ['field', 'ops.http'],
  237. ['field', 'ops.db'],
  238. ['field', 'total.time'],
  239. ['numBuckets', '100'],
  240. ]);
  241. expect(query).toEqual(
  242. 'field=ops.http&field=ops.db&field=total.time&numBuckets=100'
  243. );
  244. });
  245. });
  246. describe('getCurrentThread()', function () {
  247. it('should return current thread if available', function () {
  248. const thread = getCurrentThread(
  249. TestStubs.Event({
  250. entries: [
  251. {
  252. data: {
  253. values: [
  254. {
  255. id: 13920,
  256. current: true,
  257. crashed: true,
  258. name: 'puma 002',
  259. stacktrace: null,
  260. rawStacktrace: null,
  261. state: 'WAITING',
  262. },
  263. ],
  264. },
  265. type: EntryType.THREADS,
  266. },
  267. ],
  268. })
  269. );
  270. expect(thread?.name).toEqual('puma 002');
  271. });
  272. });
  273. describe('getThreadById()', function () {
  274. it('should return thread by given id if available', function () {
  275. const thread = getThreadById(
  276. TestStubs.Event({
  277. entries: [
  278. {
  279. data: {
  280. values: [
  281. {
  282. id: 13920,
  283. current: true,
  284. crashed: true,
  285. name: 'puma 002',
  286. stacktrace: null,
  287. rawStacktrace: null,
  288. state: 'WAITING',
  289. },
  290. ],
  291. },
  292. type: EntryType.THREADS,
  293. },
  294. ],
  295. }),
  296. 13920
  297. );
  298. expect(thread?.name).toEqual('puma 002');
  299. });
  300. });
  301. });