search_spec.rb 20 KB

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