search_spec.rb 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. # Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe 'Search', type: :request, searchindex: true do
  4. let(:group) { create(:group) }
  5. let!(:admin) do
  6. create(:admin, groups: [Group.lookup(name: 'Users'), group])
  7. end
  8. let!(:agent) do
  9. create(:agent, firstname: 'Search 1234', groups: [Group.lookup(name: 'Users'), group])
  10. end
  11. let!(:customer) do
  12. create(:customer)
  13. end
  14. let!(:organization1) do
  15. create(:organization, name: 'Rest Org')
  16. end
  17. let!(:organization2) do
  18. create(:organization, name: 'Rest Org #2')
  19. end
  20. let!(:organization3) do
  21. create(:organization, name: 'Rest Org #3')
  22. end
  23. let!(:organization4) do
  24. create(:organization, name: 'Tes.t. Org')
  25. end
  26. let!(:organization5) do
  27. create(:organization, name: 'ABC_D Org')
  28. end
  29. let!(:organization_nested) do
  30. create(:organization, name: 'Tomato42 Ltd.', note: 'Tomato42 Ltd.')
  31. end
  32. let!(:customer_nested) do
  33. create(:customer, organization: organization_nested)
  34. end
  35. let!(:customer2) do
  36. create(:customer, organization: organization1)
  37. end
  38. let!(:customer3) do
  39. create(:customer, organization: organization1)
  40. end
  41. let!(:ticket1) do
  42. create(:ticket, title: 'test 1234-1', customer: customer, group: group)
  43. end
  44. let!(:ticket2) do
  45. create(:ticket, title: 'test 1234-2', customer: customer2, group: group)
  46. end
  47. let!(:ticket3) do
  48. create(:ticket, title: 'test 1234-2', customer: customer3, group: group)
  49. end
  50. let!(:ticket_nested) do
  51. create(:ticket, title: 'vegetable request', customer: customer_nested, group: group)
  52. end
  53. let!(:article1) do
  54. create(:ticket_article, ticket_id: ticket1.id)
  55. end
  56. let!(:article2) do
  57. create(:ticket_article, ticket_id: ticket2.id)
  58. end
  59. let!(:article3) do
  60. create(:ticket_article, ticket_id: ticket3.id)
  61. end
  62. let!(:article_nested) do
  63. article = create(:ticket_article, ticket_id: ticket_nested.id)
  64. create(:store,
  65. object: 'Ticket::Article',
  66. o_id: article.id,
  67. data: File.binread(Rails.root.join('test/data/elasticsearch/es-normal.txt')),
  68. filename: 'es-normal.txt')
  69. article
  70. end
  71. before do
  72. configure_elasticsearch do
  73. travel 1.minute
  74. rebuild_searchindex
  75. # execute background jobs
  76. Scheduler.worker(true)
  77. sleep 6
  78. end
  79. end
  80. describe 'request handling' do
  81. it 'does settings index with nobody' do
  82. params = {
  83. query: 'test 1234',
  84. limit: 2,
  85. }
  86. post '/api/v1/search/ticket', params: params, as: :json
  87. expect(response).to have_http_status(:forbidden)
  88. expect(json_response).to be_a_kind_of(Hash)
  89. expect(json_response).not_to be_blank
  90. expect(json_response['error']).to eq('Authentication required')
  91. post '/api/v1/search/user', params: params, as: :json
  92. expect(response).to have_http_status(:forbidden)
  93. expect(json_response).to be_a_kind_of(Hash)
  94. expect(json_response).not_to be_blank
  95. expect(json_response['error']).to eq('Authentication required')
  96. post '/api/v1/search', params: params, as: :json
  97. expect(response).to have_http_status(:forbidden)
  98. expect(json_response).to be_a_kind_of(Hash)
  99. expect(json_response).not_to be_blank
  100. expect(json_response['error']).to eq('Authentication required')
  101. end
  102. it 'does settings index with admin' do
  103. params = {
  104. query: '1234*',
  105. limit: 1,
  106. }
  107. authenticated_as(admin)
  108. post '/api/v1/search', params: params, as: :json
  109. expect(response).to have_http_status(:ok)
  110. expect(json_response).to be_a_kind_of(Hash)
  111. expect(json_response).to be_truthy
  112. expect(json_response['result'][0]['type']).to eq('Ticket')
  113. expect(json_response['result'][0]['id']).to eq(ticket3.id)
  114. expect(json_response['result'][1]['type']).to eq('User')
  115. expect(json_response['result'][1]['id']).to eq(agent.id)
  116. expect(json_response['result'][2]).to be_falsey
  117. params = {
  118. query: '1234*',
  119. limit: 10,
  120. }
  121. post '/api/v1/search', params: params, as: :json
  122. expect(response).to have_http_status(:ok)
  123. expect(json_response).to be_a_kind_of(Hash)
  124. expect(json_response).to be_truthy
  125. expect(json_response['result'][0]['type']).to eq('Ticket')
  126. expect(json_response['result'][0]['id']).to eq(ticket3.id)
  127. expect(json_response['result'][1]['type']).to eq('Ticket')
  128. expect(json_response['result'][1]['id']).to eq(ticket2.id)
  129. expect(json_response['result'][2]['type']).to eq('Ticket')
  130. expect(json_response['result'][2]['id']).to eq(ticket1.id)
  131. expect(json_response['result'][3]['type']).to eq('User')
  132. expect(json_response['result'][3]['id']).to eq(agent.id)
  133. expect(json_response['result'][4]).to be_falsey
  134. params = {
  135. query: '1234*',
  136. limit: 10,
  137. }
  138. post '/api/v1/search/ticket', params: params, as: :json
  139. expect(response).to have_http_status(:ok)
  140. expect(json_response).to be_a_kind_of(Hash)
  141. expect(json_response).to be_truthy
  142. expect(json_response['result'][0]['type']).to eq('Ticket')
  143. expect(json_response['result'][0]['id']).to eq(ticket3.id)
  144. expect(json_response['result'][1]['type']).to eq('Ticket')
  145. expect(json_response['result'][1]['id']).to eq(ticket2.id)
  146. expect(json_response['result'][2]['type']).to eq('Ticket')
  147. expect(json_response['result'][2]['id']).to eq(ticket1.id)
  148. expect(json_response['result'][3]).to be_falsey
  149. params = {
  150. query: '1234*',
  151. limit: 10,
  152. }
  153. post '/api/v1/search/user', params: params, as: :json
  154. expect(response).to have_http_status(:ok)
  155. expect(json_response).to be_a_kind_of(Hash)
  156. expect(json_response['result'][0]['type']).to eq('User')
  157. expect(json_response['result'][0]['id']).to eq(agent.id)
  158. expect(json_response['result'][1]).to be_falsey
  159. end
  160. it 'does settings index with agent' do
  161. params = {
  162. query: '1234*',
  163. limit: 1,
  164. }
  165. authenticated_as(agent)
  166. post '/api/v1/search', params: params, as: :json
  167. expect(response).to have_http_status(:ok)
  168. expect(json_response).to be_a_kind_of(Hash)
  169. expect(json_response).to be_truthy
  170. expect(json_response['result'][0]['type']).to eq('Ticket')
  171. expect(json_response['result'][0]['id']).to eq(ticket3.id)
  172. expect(json_response['result'][1]['type']).to eq('User')
  173. expect(json_response['result'][1]['id']).to eq(agent.id)
  174. expect(json_response['result'][2]).to be_falsey
  175. params = {
  176. query: '1234*',
  177. limit: 10,
  178. }
  179. post '/api/v1/search', params: params, as: :json
  180. expect(response).to have_http_status(:ok)
  181. expect(json_response).to be_a_kind_of(Hash)
  182. expect(json_response).to be_truthy
  183. expect(json_response['result'][0]['type']).to eq('Ticket')
  184. expect(json_response['result'][0]['id']).to eq(ticket3.id)
  185. expect(json_response['result'][1]['type']).to eq('Ticket')
  186. expect(json_response['result'][1]['id']).to eq(ticket2.id)
  187. expect(json_response['result'][2]['type']).to eq('Ticket')
  188. expect(json_response['result'][2]['id']).to eq(ticket1.id)
  189. expect(json_response['result'][3]['type']).to eq('User')
  190. expect(json_response['result'][3]['id']).to eq(agent.id)
  191. expect(json_response['result'][4]).to be_falsey
  192. params = {
  193. query: '1234*',
  194. limit: 10,
  195. }
  196. post '/api/v1/search/ticket', params: params, as: :json
  197. expect(response).to have_http_status(:ok)
  198. expect(json_response).to be_a_kind_of(Hash)
  199. expect(json_response).to be_truthy
  200. expect(json_response['result'][0]['type']).to eq('Ticket')
  201. expect(json_response['result'][0]['id']).to eq(ticket3.id)
  202. expect(json_response['result'][1]['type']).to eq('Ticket')
  203. expect(json_response['result'][1]['id']).to eq(ticket2.id)
  204. expect(json_response['result'][2]['type']).to eq('Ticket')
  205. expect(json_response['result'][2]['id']).to eq(ticket1.id)
  206. expect(json_response['result'][3]).to be_falsey
  207. params = {
  208. query: '1234*',
  209. limit: 10,
  210. }
  211. post '/api/v1/search/user', params: params, as: :json
  212. expect(response).to have_http_status(:ok)
  213. expect(json_response).to be_a_kind_of(Hash)
  214. expect(json_response['result'][0]['type']).to eq('User')
  215. expect(json_response['result'][0]['id']).to eq(agent.id)
  216. expect(json_response['result'][1]).to be_falsey
  217. end
  218. it 'does settings index with customer 1' do
  219. params = {
  220. query: '1234*',
  221. limit: 10,
  222. }
  223. authenticated_as(customer)
  224. post '/api/v1/search', params: params, as: :json
  225. expect(response).to have_http_status(:ok)
  226. expect(json_response).to be_a_kind_of(Hash)
  227. expect(json_response).to be_truthy
  228. expect(json_response['result'][0]['type']).to eq('Ticket')
  229. expect(json_response['result'][0]['id']).to eq(ticket1.id)
  230. expect(json_response['result'][1]).to be_falsey
  231. params = {
  232. query: '1234*',
  233. limit: 10,
  234. }
  235. post '/api/v1/search/ticket', params: params, as: :json
  236. expect(response).to have_http_status(:ok)
  237. expect(json_response).to be_a_kind_of(Hash)
  238. expect(json_response).to be_truthy
  239. expect(json_response['result'][0]['type']).to eq('Ticket')
  240. expect(json_response['result'][0]['id']).to eq(ticket1.id)
  241. expect(json_response['result'][1]).to be_falsey
  242. params = {
  243. query: '1234*',
  244. limit: 10,
  245. }
  246. post '/api/v1/search/user', params: params, as: :json
  247. expect(response).to have_http_status(:ok)
  248. expect(json_response).to be_a_kind_of(Hash)
  249. expect(json_response['result'][0]).to be_falsey
  250. end
  251. it 'does settings index with customer 2' do
  252. params = {
  253. query: '1234*',
  254. limit: 10,
  255. }
  256. authenticated_as(customer2)
  257. post '/api/v1/search', params: params, as: :json
  258. expect(response).to have_http_status(:ok)
  259. expect(json_response).to be_a_kind_of(Hash)
  260. expect(json_response).to be_truthy
  261. expect(json_response['result'][0]['type']).to eq('Ticket')
  262. expect(json_response['result'][0]['id']).to eq(ticket3.id)
  263. expect(json_response['result'][1]['type']).to eq('Ticket')
  264. expect(json_response['result'][1]['id']).to eq(ticket2.id)
  265. expect(json_response['result'][2]).to be_falsey
  266. params = {
  267. query: '1234*',
  268. limit: 10,
  269. }
  270. post '/api/v1/search/ticket', params: params, as: :json
  271. expect(response).to have_http_status(:ok)
  272. expect(json_response).to be_a_kind_of(Hash)
  273. expect(json_response).to be_truthy
  274. expect(json_response['result'][0]['type']).to eq('Ticket')
  275. expect(json_response['result'][0]['id']).to eq(ticket3.id)
  276. expect(json_response['result'][1]['type']).to eq('Ticket')
  277. expect(json_response['result'][1]['id']).to eq(ticket2.id)
  278. expect(json_response['result'][2]).to be_falsey
  279. params = {
  280. query: '1234*',
  281. limit: 10,
  282. }
  283. post '/api/v1/search/user', params: params, as: :json
  284. expect(response).to have_http_status(:ok)
  285. expect(json_response).to be_a_kind_of(Hash)
  286. expect(json_response['result'][0]).to be_falsey
  287. end
  288. # Verify fix for Github issue #2058 - Autocomplete hangs on dot in the new user form
  289. it 'does searching for organization with a dot in its name' do
  290. authenticated_as(agent)
  291. get '/api/v1/search/organization?query=tes.', as: :json
  292. expect(response).to have_http_status(:ok)
  293. expect(json_response['result'].size).to eq(1)
  294. expect(json_response['result'][0]['type']).to eq('Organization')
  295. target_id = json_response['result'][0]['id']
  296. expect(json_response['assets']['Organization'][target_id.to_s]['name']).to eq('Tes.t. Org')
  297. end
  298. # Search query H& should correctly match H&M
  299. it 'does searching for organization with _ in its name' do
  300. authenticated_as(agent)
  301. get '/api/v1/search/organization?query=abc_', as: :json
  302. expect(response).to have_http_status(:ok)
  303. expect(json_response['result'].size).to eq(1)
  304. expect(json_response['result'][0]['type']).to eq('Organization')
  305. target_id = json_response['result'][0]['id']
  306. expect(json_response['assets']['Organization'][target_id.to_s]['name']).to eq('ABC_D Org')
  307. end
  308. it 'does find the user of the nested organization and also even if the organization name changes' do
  309. # because of the initial relation between user and organization
  310. # both user and organization will be found as result
  311. authenticated_as(agent)
  312. post '/api/v1/search/User', params: { query: 'Tomato42' }, as: :json
  313. expect(response).to have_http_status(:ok)
  314. expect(json_response).to be_a_kind_of(Hash)
  315. expect(json_response).to be_truthy
  316. expect(json_response['assets']['Organization'][organization_nested.id.to_s]).to be_truthy
  317. expect(json_response['assets']['User'][customer_nested.id.to_s]).to be_truthy
  318. post '/api/v1/search/User', params: { query: 'organization.name:Tomato42' }, as: :json
  319. expect(response).to have_http_status(:ok)
  320. expect(json_response).to be_a_kind_of(Hash)
  321. expect(json_response).to be_truthy
  322. expect(json_response['assets']['Organization'][organization_nested.id.to_s]).to be_truthy
  323. expect(json_response['assets']['User'][customer_nested.id.to_s]).to be_truthy
  324. organization_nested.update(name: 'Cucumber43 Ltd.')
  325. Scheduler.worker(true)
  326. SearchIndexBackend.refresh
  327. # even after a change of the organization name we should find
  328. # the customer user because of the nested organization data
  329. post '/api/v1/search/User', params: { query: 'Cucumber43' }, as: :json
  330. expect(response).to have_http_status(:ok)
  331. expect(json_response).to be_a_kind_of(Hash)
  332. expect(json_response).to be_truthy
  333. expect(json_response['assets']['Organization'][organization_nested.id.to_s]).to be_truthy
  334. expect(json_response['assets']['User'][customer_nested.id.to_s]).to be_truthy
  335. post '/api/v1/search/User', params: { query: 'organization.name:Cucumber43' }, as: :json
  336. expect(response).to have_http_status(:ok)
  337. expect(json_response).to be_a_kind_of(Hash)
  338. expect(json_response).to be_truthy
  339. expect(json_response['assets']['Organization'][organization_nested.id.to_s]).to be_truthy
  340. expect(json_response['assets']['User'][customer_nested.id.to_s]).to be_truthy
  341. end
  342. it 'does find the ticket by organization name even if the organization name changes' do
  343. authenticated_as(agent)
  344. post '/api/v1/search/Ticket', params: { query: 'Tomato42' }, as: :json
  345. expect(response).to have_http_status(:ok)
  346. expect(json_response).to be_a_kind_of(Hash)
  347. expect(json_response).to be_truthy
  348. expect(json_response['assets']['Organization'][organization_nested.id.to_s]).to be_truthy
  349. expect(json_response['assets']['Ticket'][ticket_nested.id.to_s]).to be_truthy
  350. post '/api/v1/search/Ticket', params: { query: 'organization.name:Tomato42' }, as: :json
  351. expect(response).to have_http_status(:ok)
  352. expect(json_response).to be_a_kind_of(Hash)
  353. expect(json_response).to be_truthy
  354. expect(json_response['assets']['Organization'][organization_nested.id.to_s]).to be_truthy
  355. expect(json_response['assets']['Ticket'][ticket_nested.id.to_s]).to be_truthy
  356. organization_nested.update(name: 'Cucumber43 Ltd.')
  357. Scheduler.worker(true)
  358. SearchIndexBackend.refresh
  359. post '/api/v1/search/Ticket', params: { query: 'Cucumber43' }, as: :json
  360. expect(response).to have_http_status(:ok)
  361. expect(json_response).to be_a_kind_of(Hash)
  362. expect(json_response).to be_truthy
  363. expect(json_response['assets']['Organization'][organization_nested.id.to_s]).to be_truthy
  364. expect(json_response['assets']['Ticket'][ticket_nested.id.to_s]).to be_truthy
  365. post '/api/v1/search/Ticket', params: { query: 'organization.name:Cucumber43' }, as: :json
  366. expect(response).to have_http_status(:ok)
  367. expect(json_response).to be_a_kind_of(Hash)
  368. expect(json_response).to be_truthy
  369. expect(json_response['assets']['Organization'][organization_nested.id.to_s]).to be_truthy
  370. expect(json_response['assets']['Ticket'][ticket_nested.id.to_s]).to be_truthy
  371. end
  372. it 'does find the ticket by group name even if the group name changes' do
  373. authenticated_as(agent)
  374. post '/api/v1/search/Ticket', params: { query: "number:#{ticket1.number} && group.name:ultrasupport" }, as: :json
  375. expect(response).to have_http_status(:ok)
  376. expect(json_response).to be_a_kind_of(Hash)
  377. expect(json_response).to be_truthy
  378. expect(json_response['assets']['Ticket']).to be_falsey
  379. expect(group).not_to eq('ultrasupport')
  380. group.update(name: 'ultrasupport')
  381. Scheduler.worker(true)
  382. SearchIndexBackend.refresh
  383. post '/api/v1/search/Ticket', params: { query: "number:#{ticket1.number} && group.name:ultrasupport" }, as: :json
  384. expect(response).to have_http_status(:ok)
  385. expect(json_response).to be_a_kind_of(Hash)
  386. expect(json_response).to be_truthy
  387. expect(json_response['assets']['Ticket'][ticket1.id.to_s]).to be_truthy
  388. end
  389. it 'does find the ticket by state name even if the state name changes' do
  390. authenticated_as(agent)
  391. post '/api/v1/search/Ticket', params: { query: "number:#{ticket1.number} && state.name:ultrastate" }, as: :json
  392. expect(response).to have_http_status(:ok)
  393. expect(json_response).to be_a_kind_of(Hash)
  394. expect(json_response).to be_truthy
  395. expect(json_response['assets']['Ticket']).to be_falsey
  396. expect(ticket1.state.name).not_to eq('ultrastate')
  397. ticket1.state.update(name: 'ultrastate')
  398. Scheduler.worker(true)
  399. SearchIndexBackend.refresh
  400. post '/api/v1/search/Ticket', params: { query: "number:#{ticket1.number} && state.name:ultrastate" }, as: :json
  401. expect(response).to have_http_status(:ok)
  402. expect(json_response).to be_a_kind_of(Hash)
  403. expect(json_response).to be_truthy
  404. expect(json_response['assets']['Ticket'][ticket1.id.to_s]).to be_truthy
  405. end
  406. it 'does find the ticket by priority name even if the priority name changes' do
  407. authenticated_as(agent)
  408. post '/api/v1/search/Ticket', params: { query: "number:#{ticket1.number} && priority.name:ultrapriority" }, as: :json
  409. expect(response).to have_http_status(:ok)
  410. expect(json_response).to be_a_kind_of(Hash)
  411. expect(json_response).to be_truthy
  412. expect(json_response['assets']['Ticket']).to be_falsey
  413. expect(ticket1.priority.name).not_to eq('ultrapriority')
  414. ticket1.priority.update(name: 'ultrapriority')
  415. Scheduler.worker(true)
  416. SearchIndexBackend.refresh
  417. post '/api/v1/search/Ticket', params: { query: "number:#{ticket1.number} && priority.name:ultrapriority" }, as: :json
  418. expect(response).to have_http_status(:ok)
  419. expect(json_response).to be_a_kind_of(Hash)
  420. expect(json_response).to be_truthy
  421. expect(json_response['assets']['Ticket'][ticket1.id.to_s]).to be_truthy
  422. end
  423. it 'does find the ticket by attachment even after ticket reindex' do
  424. params = {
  425. query: 'text66',
  426. limit: 10,
  427. }
  428. authenticated_as(agent)
  429. post '/api/v1/search/Ticket', params: params, as: :json
  430. expect(response).to have_http_status(:ok)
  431. expect(json_response).to be_a_kind_of(Hash)
  432. expect(json_response).to be_truthy
  433. expect(json_response['assets']['Ticket'][ticket_nested.id.to_s]).to be_truthy
  434. organization_nested.update(name: 'Cucumber43 Ltd.')
  435. Scheduler.worker(true)
  436. SearchIndexBackend.refresh
  437. params = {
  438. query: 'text66',
  439. limit: 10,
  440. }
  441. post '/api/v1/search/Ticket', params: params, as: :json
  442. expect(response).to have_http_status(:ok)
  443. expect(json_response).to be_a_kind_of(Hash)
  444. expect(json_response).to be_truthy
  445. expect(json_response['assets']['Ticket'][ticket_nested.id.to_s]).to be_truthy
  446. end
  447. end
  448. end