caller_id_spec.rb 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. require 'rails_helper'
  2. RSpec.describe Cti::CallerId do
  3. describe '.extract_numbers' do
  4. context 'for strings containing arbitrary numbers (<6 digits long)' do
  5. it 'returns an empty array' do
  6. expect(described_class.extract_numbers(<<~INPUT.chomp)).to be_empty
  7. some text
  8. test 123
  9. INPUT
  10. end
  11. end
  12. context 'for strings containing a phone number with "(0)" after country code' do
  13. it 'returns the number in an array, without the leading "(0)"' do
  14. expect(described_class.extract_numbers(<<~INPUT.chomp)).to eq(['4930600000000'])
  15. Lorem ipsum dolor sit amet, consectetuer +49 (0) 30 60 00 00 00-0
  16. adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa.
  17. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur
  18. ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu,
  19. pretium quis, sem. Nulla consequat massa quis enim. Donec pede
  20. justo, fringilla vel.
  21. INPUT
  22. end
  23. end
  24. context 'for strings containing a phone number with leading 0 (no country code)' do
  25. it 'returns the number in an array, using default country code (49)' do
  26. expect(described_class.extract_numbers(<<~INPUT.chomp)).to eq(['4994221000'])
  27. GS Oberalteich
  28. Telefon 09422 1000
  29. E-Mail:
  30. INPUT
  31. end
  32. end
  33. context 'for strings containing multiple phone numbers' do
  34. it 'returns all numbers in an array' do
  35. expect(described_class.extract_numbers(<<~INPUT.chomp)).to eq(%w[41812886393 41763467214])
  36. Tel +41 81 288 63 93 / +41 76 346 72 14 ...
  37. INPUT
  38. end
  39. end
  40. context 'for strings containing US-formatted numbers' do
  41. it 'returns the numbers in an array correctly' do
  42. expect(described_class.extract_numbers(<<~INPUT.chomp)).to eq(%w[19494310000 19494310001])
  43. P: +1 (949) 431 0000
  44. F: +1 (949) 431 0001
  45. W: http://znuny
  46. INPUT
  47. end
  48. end
  49. end
  50. describe '.normalize_number' do
  51. it 'does not modify digit-only strings (starting with 1-9)' do
  52. expect(described_class.normalize_number('5754321')).to eq('5754321')
  53. end
  54. it 'strips whitespace' do
  55. expect(described_class.normalize_number('622 32281')).to eq('62232281')
  56. end
  57. it 'strips hyphens' do
  58. expect(described_class.normalize_number('1-888-407-4747')).to eq('18884074747')
  59. end
  60. it 'strips leading pluses' do
  61. expect(described_class.normalize_number('+49 30 53 00 00 000')).to eq('4930530000000')
  62. expect(described_class.normalize_number('+49 160 0000000')).to eq('491600000000')
  63. end
  64. it 'replaces a single leading zero with the default country code (49)' do
  65. expect(described_class.normalize_number('092213212')).to eq('4992213212')
  66. expect(described_class.normalize_number('0271233211')).to eq('49271233211')
  67. expect(described_class.normalize_number('022 1234567')).to eq('49221234567')
  68. expect(described_class.normalize_number('09 123 32112')).to eq('49912332112')
  69. expect(described_class.normalize_number('021 2331231')).to eq('49212331231')
  70. expect(described_class.normalize_number('021 321123123')).to eq('4921321123123')
  71. expect(described_class.normalize_number('0150 12345678')).to eq('4915012345678')
  72. expect(described_class.normalize_number('021-233-9123')).to eq('49212339123')
  73. end
  74. it 'strips two leading zeroes' do
  75. expect(described_class.normalize_number('0049 1234 123456789')).to eq('491234123456789')
  76. expect(described_class.normalize_number('0043 30 60 00 00 00-0')).to eq('4330600000000')
  77. end
  78. it 'strips leading zero from "(0x)" at start of number or after country code' do
  79. expect(described_class.normalize_number('(09)1234321')).to eq('4991234321')
  80. expect(described_class.normalize_number('+49 (0) 30 60 00 00 00-0')).to eq('4930600000000')
  81. expect(described_class.normalize_number('0043 (0) 30 60 00 00 00-0')).to eq('4330600000000')
  82. end
  83. end
  84. describe '.lookup' do
  85. context 'when given an unrecognized number' do
  86. it 'returns an empty array' do
  87. expect(described_class.lookup('1')).to eq([])
  88. end
  89. end
  90. context 'when given a recognized number' do
  91. subject!(:caller_id) { create(:caller_id, caller_id: number) }
  92. let(:number) { '1234567890' }
  93. it 'returns an array with the corresponding CallerId' do
  94. expect(described_class.lookup(number)).to match_array([caller_id])
  95. end
  96. context 'shared by multiple CallerIds' do
  97. context '(for different users)' do
  98. subject!(:caller_ids) do
  99. [create(:caller_id, caller_id: number, user: create(:user)),
  100. create(:caller_id, caller_id: number, user: create(:user))]
  101. end
  102. it 'returns all corresponding CallerId records' do
  103. expect(described_class.lookup(number)).to match_array(caller_ids)
  104. end
  105. end
  106. context '(for the same user)' do
  107. subject!(:caller_ids) { create_list(:caller_id, 2, caller_id: number) }
  108. it 'returns one corresponding CallerId record by MAX(id)' do
  109. expect(described_class.lookup(number)).to match_array(caller_ids.last(1))
  110. end
  111. end
  112. context '(some for the same user, some for another)' do
  113. subject!(:caller_ids) do
  114. [*create_list(:caller_id, 2, caller_id: number, user: create(:user)),
  115. create(:caller_id, caller_id: number, user: create(:user))]
  116. end
  117. it 'returns one CallerId record per unique #user_id, by MAX(id)' do
  118. expect(described_class.lookup(number)).to match_array(caller_ids.last(2))
  119. end
  120. end
  121. end
  122. end
  123. end
  124. describe '.rebuild' do
  125. context 'when a User record contains a valid phone number' do
  126. let!(:user) { create(:agent_user, phone: '+49 123 456') }
  127. context 'and no corresponding CallerId exists' do
  128. it 'generates a CallerId record (with #level "known")' do
  129. described_class.destroy_all # CallerId already generated in User callback
  130. expect { described_class.rebuild }
  131. .to change { described_class.exists?(user_id: user.id, caller_id: '49123456', level: 'known') }
  132. .to(true)
  133. end
  134. end
  135. it 'does not create duplicate CallerId records' do
  136. expect { described_class.rebuild }.not_to change(described_class, :count)
  137. end
  138. end
  139. context 'when no User exists for a given CallerId record' do
  140. subject!(:caller_id) { create(:caller_id) }
  141. it 'deletes the CallerId record' do
  142. expect { described_class.rebuild }
  143. .to change { described_class.exists?(caller_id.id) }.to(false)
  144. end
  145. end
  146. context 'when two User records contains the same valid phone number' do
  147. let!(:users) { create_list(:agent_user, 2, phone: '+49 123 456') }
  148. it 'generates two corresponding CallerId records (with #level "known")' do
  149. described_class.destroy_all # CallerId already generated in User callback
  150. expect { described_class.rebuild }
  151. .to change { described_class.exists?(user_id: users.first.id, caller_id: '49123456', level: 'known') }
  152. .to(true)
  153. .and change { described_class.exists?(user_id: users.last.id, caller_id: '49123456', level: 'known') }
  154. .to(true)
  155. end
  156. end
  157. context 'when an Article record contains a valid phone number in its body' do
  158. let!(:article) { create(:ticket_article, body: <<~BODY, sender_name: sender_name) }
  159. some message
  160. Fon (GEL): +49 123-456 Mi-Fr
  161. BODY
  162. context 'and comes from a customer' do
  163. let(:sender_name) { 'Customer' }
  164. it 'generates a CallerId record (with #level "maybe")' do
  165. described_class.destroy_all # CallerId already generated in Article observer job
  166. expect { described_class.rebuild }
  167. .to change { described_class.exists?(user_id: article.created_by_id, caller_id: '49123456', level: 'maybe') }
  168. .to(true)
  169. end
  170. end
  171. context 'and comes from an Agent' do
  172. let(:sender_name) { 'Agent' }
  173. it 'does not generate a CallerId record' do
  174. expect { described_class.rebuild }
  175. .not_to change { described_class.exists?(caller_id: '49123456') }
  176. end
  177. end
  178. end
  179. end
  180. describe '.maybe_add' do
  181. let(:attributes) { attributes_for(:caller_id) }
  182. it 'wraps .find_or_initialize_by (passing only five defining attributes)' do
  183. expect(described_class)
  184. .to receive(:find_or_initialize_by)
  185. .with(attributes.slice(:caller_id, :level, :object, :o_id, :user_id))
  186. .and_call_original
  187. described_class.maybe_add(attributes)
  188. end
  189. context 'if no matching record found' do
  190. it 'adds given #comment attribute' do
  191. expect { described_class.maybe_add(attributes.merge(comment: 'foo')) }
  192. .to change(described_class, :count).by(1)
  193. expect(described_class.last.comment).to eq('foo')
  194. end
  195. end
  196. context 'if matching record found' do
  197. let(:attributes) { caller_id.attributes.symbolize_keys }
  198. let(:caller_id) { create(:caller_id) }
  199. it 'ignores given #comment attribute' do
  200. expect(described_class.maybe_add(attributes.merge(comment: 'foo')))
  201. .to eq(caller_id)
  202. expect(caller_id.comment).to be_blank
  203. end
  204. end
  205. end
  206. describe '.known_agents_by_number' do
  207. context 'with known agent caller_id' do
  208. let!(:agent_user1) { create(:agent_user, phone: '0123456') }
  209. let!(:agent_user2) { create(:agent_user, phone: '0123457') }
  210. it 'gives matching agents' do
  211. expect(described_class.known_agents_by_number('49123456'))
  212. .to match_array([agent_user1])
  213. end
  214. end
  215. context 'with known customer caller_id' do
  216. let!(:customer_user1) { create(:customer_user, phone: '0123456') }
  217. it 'returns an empty array' do
  218. expect(described_class.known_agents_by_number('49123456')).to eq([])
  219. end
  220. end
  221. context 'with maybe caller_id' do
  222. let(:ticket1) do
  223. create(:ticket_article, created_by_id: customer_user2.id, body: 'some text 0123457') # create ticket
  224. Observer::Transaction.commit
  225. Scheduler.worker(true)
  226. end
  227. let!(:customer_user2) { create(:customer_user) }
  228. it 'returns an empty array' do
  229. expect(described_class.known_agents_by_number('49123457').count).to eq(0)
  230. end
  231. end
  232. end
  233. describe 'callbacks' do
  234. subject!(:caller_id) { build(:cti_caller_id, caller_id: phone) }
  235. let(:phone) { '1234567890' }
  236. describe 'on creation' do
  237. it 'adopts CTI Logs from same number (via UpdateCtiLogsByCallerJob)' do
  238. expect(UpdateCtiLogsByCallerJob).to receive(:perform_later)
  239. caller_id.save
  240. end
  241. it 'splits job into fg and bg (for more responsive UI – see #2057)' do
  242. expect(UpdateCtiLogsByCallerJob).to receive(:perform_now).with(phone, limit: 20)
  243. expect(UpdateCtiLogsByCallerJob).to receive(:perform_later).with(phone, limit: 40, offset: 20)
  244. caller_id.save
  245. end
  246. end
  247. describe 'on destruction' do
  248. before { caller_id.save }
  249. it 'orphans CTI Logs from same number (via UpdateCtiLogsByCallerJob)' do
  250. expect(UpdateCtiLogsByCallerJob).to receive(:perform_later).with(phone)
  251. caller_id.destroy
  252. end
  253. end
  254. end
  255. end