1# frozen_string_literal: true
2
3require "test_helper"
4require "customer"
5require "registration"
6
7def execute_command(
8 iq=Blather::Stanza::Iq::Command.new.tap { |i| i.from = "test@example.com" },
9 blather: BLATHER,
10 &blk
11)
12 Command::Execution.new(
13 Minitest::Mock.new,
14 blather,
15 :to_s.to_proc,
16 iq
17 ).execute(&blk).sync
18end
19
20class RegistrationTest < Minitest::Test
21 def test_for_registered
22 sgx = OpenStruct.new(
23 registered?: EMPromise.resolve(OpenStruct.new(phone: "+15555550000"))
24 )
25 iq = Blather::Stanza::Iq::Command.new
26 iq.from = "test@example.com"
27 result = execute_command(iq) do
28 Registration.for(
29 Customer.new("test", sgx: sgx),
30 Minitest::Mock.new
31 )
32 end
33 assert_kind_of Registration::Registered, result
34 end
35 em :test_for_registered
36
37 def test_for_activated
38 sgx = OpenStruct.new(registered?: EMPromise.resolve(nil))
39 web_manager = WebRegisterManager.new
40 web_manager["test@example.com"] = "+15555550000"
41 iq = Blather::Stanza::Iq::Command.new
42 iq.from = "test@example.com"
43 result = execute_command(iq) do
44 Registration.for(
45 Customer.new(
46 "test",
47 plan_name: "test_usd",
48 expires_at: Time.now + 999,
49 sgx: sgx
50 ),
51 web_manager
52 )
53 end
54 assert_kind_of Registration::Finish, result
55 end
56 em :test_for_activated
57
58 def test_for_not_activated_with_customer_id
59 sgx = OpenStruct.new(registered?: EMPromise.resolve(nil))
60 web_manager = WebRegisterManager.new
61 web_manager["test@example.com"] = "+15555550000"
62 iq = Blather::Stanza::Iq::Command.new
63 iq.from = "test@example.com"
64 result = execute_command(iq) do
65 Registration.for(
66 Customer.new("test", sgx: sgx),
67 web_manager
68 )
69 end
70 assert_kind_of Registration::Activation, result
71 end
72 em :test_for_not_activated_with_customer_id
73
74 class ActivationTest < Minitest::Test
75 Command::COMMAND_MANAGER = Minitest::Mock.new
76 def setup
77 @activation = Registration::Activation.new("test", "+15555550000")
78 end
79
80 def test_write
81 stub_request(
82 :get,
83 "https://dashboard.bandwidth.com/v1.0/tns/+15555550000"
84 ).to_return(status: 201, body: <<~RESPONSE)
85 <TelephoneNumberResponse>
86 <TelephoneNumber>5555550000</TelephoneNumber>
87 </TelephoneNumberResponse>
88 RESPONSE
89 stub_request(
90 :get,
91 "https://dashboard.bandwidth.com/v1.0/tns/5555550000/ratecenter"
92 ).to_return(status: 201, body: <<~RESPONSE)
93 <TelephoneNumberResponse>
94 <TelephoneNumberDetails>
95 <State>KE</State>
96 <RateCenter>FA</RateCenter>
97 </TelephoneNumberDetails>
98 </TelephoneNumberResponse>
99 RESPONSE
100 Command::COMMAND_MANAGER.expect(
101 :write,
102 EMPromise.reject(:test_result),
103 [Matching.new do |iq|
104 assert_equal :form, iq.form.type
105 assert_equal(
106 "You've selected +15555550000 (FA, KE) as your JMP number",
107 iq.form.instructions
108 )
109 end]
110 )
111 assert_equal(
112 :test_result,
113 execute_command { @activation.write.catch { |e| e } }
114 )
115 assert_mock Command::COMMAND_MANAGER
116 end
117 em :test_write
118 end
119
120 class PaymentTest < Minitest::Test
121 Customer::BRAINTREE = Minitest::Mock.new
122
123 def test_for_bitcoin
124 customer = Minitest::Mock.new(Customer.new("test"))
125 customer.expect(
126 :add_btc_address,
127 EMPromise.resolve("testaddr")
128 )
129 iq = Blather::Stanza::Iq::Command.new
130 iq.form.fields = [
131 { var: "activation_method", value: "bitcoin" },
132 { var: "plan_name", value: "test_usd" }
133 ]
134 result = Registration::Payment.for(iq, customer, "+15555550000")
135 assert_kind_of Registration::Payment::Bitcoin, result
136 end
137
138 def test_for_credit_card
139 braintree_customer = Minitest::Mock.new
140 Customer::BRAINTREE.expect(
141 :customer,
142 braintree_customer
143 )
144 braintree_customer.expect(
145 :find,
146 EMPromise.resolve(OpenStruct.new(payment_methods: [])),
147 ["test"]
148 )
149 iq = Blather::Stanza::Iq::Command.new
150 iq.from = "test@example.com"
151 iq.form.fields = [
152 { var: "activation_method", value: "credit_card" },
153 { var: "plan_name", value: "test_usd" }
154 ]
155 result = Registration::Payment.for(
156 iq,
157 Customer.new("test"),
158 "+15555550000"
159 ).sync
160 assert_kind_of Registration::Payment::CreditCard, result
161 end
162 em :test_for_credit_card
163
164 def test_for_code
165 iq = Blather::Stanza::Iq::Command.new
166 iq.form.fields = [
167 { var: "activation_method", value: "code" },
168 { var: "plan_name", value: "test_usd" }
169 ]
170 result = Registration::Payment.for(
171 iq,
172 Customer.new("test"),
173 "+15555550000"
174 )
175 assert_kind_of Registration::Payment::InviteCode, result
176 end
177
178 class BitcoinTest < Minitest::Test
179 Registration::Payment::Bitcoin::BTC_SELL_PRICES = Minitest::Mock.new
180 Customer::REDIS = Minitest::Mock.new
181
182 def setup
183 @customer = Minitest::Mock.new(
184 Customer.new("test", plan_name: "test_usd")
185 )
186 @customer.expect(
187 :add_btc_address,
188 EMPromise.resolve("testaddr")
189 )
190 @bitcoin = Registration::Payment::Bitcoin.new(
191 @customer,
192 "+15555550000"
193 )
194 end
195
196 def test_write
197 Customer::REDIS.expect(
198 :smembers,
199 EMPromise.resolve([]),
200 ["jmp_customer_btc_addresses-test"]
201 )
202 reply_text = <<~NOTE
203 Activate your account by sending at least 1.000000 BTC to
204 testaddr
205
206 You will receive a notification when your payment is complete.
207 NOTE
208 blather = Minitest::Mock.new
209 blather.expect(
210 :<<,
211 nil,
212 [Matching.new do |reply|
213 assert_equal :canceled, reply.status
214 assert_equal :info, reply.note_type
215 assert_equal reply_text, reply.note.content
216 true
217 end]
218 )
219 Registration::Payment::Bitcoin::BTC_SELL_PRICES.expect(
220 :usd,
221 EMPromise.resolve(BigDecimal.new(1))
222 )
223 @bitcoin.stub(:save, EMPromise.resolve(nil)) do
224 execute_command(blather: blather) do
225 @bitcoin.write
226 end
227 end
228 assert_mock blather
229 end
230 em :test_write
231 end
232
233 class CreditCardTest < Minitest::Test
234 def setup
235 @credit_card = Registration::Payment::CreditCard.new(
236 Customer.new("test"),
237 "+15555550000"
238 )
239 end
240
241 def test_for
242 customer = Minitest::Mock.new(Customer.new("test"))
243 customer.expect(
244 :payment_methods,
245 EMPromise.resolve(OpenStruct.new(default_payment_method: :test))
246 )
247 assert_kind_of(
248 Registration::Payment::CreditCard::Activate,
249 Registration::Payment::CreditCard.for(
250 customer,
251 "+15555550000"
252 ).sync
253 )
254 end
255 em :test_for
256
257 def test_write
258 result = execute_command do
259 Command::COMMAND_MANAGER.expect(
260 :write,
261 EMPromise.reject(:test_result),
262 [Matching.new do |reply|
263 assert_equal [:execute, :next], reply.allowed_actions
264 assert_equal(
265 "Add credit card, then return here to continue: " \
266 "http://creditcard.example.com",
267 reply.note.content
268 )
269 end]
270 )
271
272 @credit_card.write.catch { |e| e }
273 end
274
275 assert_equal :test_result, result
276 end
277 em :test_write
278 end
279
280 class ActivateTest < Minitest::Test
281 Registration::Payment::CreditCard::Activate::Finish =
282 Minitest::Mock.new
283 Registration::Payment::CreditCard::Activate::Transaction =
284 Minitest::Mock.new
285 Command::COMMAND_MANAGER = Minitest::Mock.new
286
287 def test_write
288 transaction = PromiseMock.new
289 transaction.expect(
290 :insert,
291 EMPromise.resolve(nil)
292 )
293 customer = Minitest::Mock.new(
294 Customer.new("test", plan_name: "test_usd")
295 )
296 Registration::Payment::CreditCard::Activate::Transaction.expect(
297 :sale,
298 transaction
299 ) do |acustomer, amount:, payment_method:|
300 assert_operator customer, :===, acustomer
301 assert_equal CONFIG[:activation_amount], amount
302 assert_equal :test_default_method, payment_method
303 end
304 customer.expect(:bill_plan, nil)
305 Registration::Payment::CreditCard::Activate::Finish.expect(
306 :new,
307 OpenStruct.new(write: nil),
308 [customer, "+15555550000"]
309 )
310 execute_command do
311 Registration::Payment::CreditCard::Activate.new(
312 customer,
313 :test_default_method,
314 "+15555550000"
315 ).write
316 end
317 Registration::Payment::CreditCard::Activate::Transaction.verify
318 transaction.verify
319 customer.verify
320 Registration::Payment::CreditCard::Activate::Finish.verify
321 end
322 em :test_write
323
324 def test_write_declines
325 customer = Minitest::Mock.new(
326 Customer.new("test", plan_name: "test_usd")
327 )
328 iq = Blather::Stanza::Iq::Command.new
329 iq.from = "test@example.com"
330 Command::COMMAND_MANAGER.expect(
331 :write,
332 EMPromise.reject(:test_result),
333 [Matching.new do |reply|
334 assert_equal :error, reply.note_type
335 assert_equal(
336 Registration::Payment::CreditCard::Activate::DECLINE_MESSAGE +
337 ": http://creditcard.example.com",
338 reply.note.content
339 )
340 end]
341 )
342 result = execute_command do
343 Registration::Payment::CreditCard::Activate::Transaction.expect(
344 :sale,
345 EMPromise.reject("declined")
346 ) do |acustomer, amount:, payment_method:|
347 assert_operator customer, :===, acustomer
348 assert_equal CONFIG[:activation_amount], amount
349 assert_equal :test_default_method, payment_method
350 end
351
352 Registration::Payment::CreditCard::Activate.new(
353 customer,
354 :test_default_method,
355 "+15555550000"
356 ).write.catch { |e| e }
357 end
358 assert_equal :test_result, result
359 Registration::Payment::CreditCard::Activate::Transaction.verify
360 end
361 em :test_write_declines
362 end
363
364 class InviteCodeTest < Minitest::Test
365 Registration::Payment::InviteCode::DB =
366 Minitest::Mock.new
367 Registration::Payment::InviteCode::REDIS =
368 Minitest::Mock.new
369 Command::COMMAND_MANAGER = Minitest::Mock.new
370 Registration::Payment::InviteCode::Finish =
371 Minitest::Mock.new
372 def test_write
373 customer = Customer.new("test", plan_name: "test_usd")
374 Registration::Payment::InviteCode::DB.expect(:transaction, true, [])
375 Registration::Payment::InviteCode::Finish.expect(
376 :new,
377 OpenStruct.new(write: nil),
378 [
379 customer,
380 "+15555550000"
381 ]
382 )
383 execute_command do
384 Registration::Payment::InviteCode::REDIS.expect(
385 :get,
386 EMPromise.resolve(nil),
387 ["jmp_invite_tries-test"]
388 )
389 Command::COMMAND_MANAGER.expect(
390 :write,
391 EMPromise.resolve(
392 Blather::Stanza::Iq::Command.new.tap { |iq|
393 iq.form.fields = [{ var: "code", value: "abc" }]
394 }
395 ),
396 [Matching.new do |reply|
397 assert_equal :form, reply.form.type
398 assert_nil reply.form.instructions
399 end]
400 )
401
402 Registration::Payment::InviteCode.new(
403 customer,
404 "+15555550000"
405 ).write
406 end
407 assert_mock Command::COMMAND_MANAGER
408 assert_mock Registration::Payment::InviteCode::DB
409 assert_mock Registration::Payment::InviteCode::REDIS
410 assert_mock Registration::Payment::InviteCode::Finish
411 end
412 em :test_write
413
414 def test_write_bad_code
415 result = execute_command do
416 customer = Customer.new("test", plan_name: "test_usd")
417 Registration::Payment::InviteCode::REDIS.expect(
418 :get,
419 EMPromise.resolve(0),
420 ["jmp_invite_tries-test"]
421 )
422 Registration::Payment::InviteCode::DB.expect(:transaction, []) do
423 raise Registration::Payment::InviteCode::Invalid, "wut"
424 end
425 Registration::Payment::InviteCode::REDIS.expect(
426 :incr,
427 EMPromise.resolve(nil),
428 ["jmp_invite_tries-test"]
429 )
430 Registration::Payment::InviteCode::REDIS.expect(
431 :expire,
432 EMPromise.resolve(nil),
433 ["jmp_invite_tries-test", 60 * 60]
434 )
435 Command::COMMAND_MANAGER.expect(
436 :write,
437 EMPromise.resolve(
438 Blather::Stanza::Iq::Command.new.tap { |iq|
439 iq.form.fields = [{ var: "code", value: "abc" }]
440 }
441 ),
442 [Matching.new do |reply|
443 assert_equal :form, reply.form.type
444 assert_nil reply.form.instructions
445 end]
446 )
447 Command::COMMAND_MANAGER.expect(
448 :write,
449 EMPromise.reject(:test_result),
450 [Matching.new do |reply|
451 assert_equal :form, reply.form.type
452 assert_equal "wut", reply.form.instructions
453 end]
454 )
455
456 Registration::Payment::InviteCode.new(
457 customer,
458 "+15555550000"
459 ).write.catch { |e| e }
460 end
461 assert_equal :test_result, result
462 assert_mock Command::COMMAND_MANAGER
463 assert_mock Registration::Payment::InviteCode::DB
464 assert_mock Registration::Payment::InviteCode::REDIS
465 end
466 em :test_write_bad_code
467
468 def test_write_bad_code_over_limit
469 result = execute_command do
470 customer = Customer.new("test", plan_name: "test_usd")
471 Registration::Payment::InviteCode::REDIS.expect(
472 :get,
473 EMPromise.resolve(11),
474 ["jmp_invite_tries-test"]
475 )
476 Command::COMMAND_MANAGER.expect(
477 :write,
478 EMPromise.resolve(
479 Blather::Stanza::Iq::Command.new.tap { |iq|
480 iq.form.fields = [{ var: "code", value: "abc" }]
481 }
482 ),
483 [Matching.new do |reply|
484 assert_equal :form, reply.form.type
485 assert_nil reply.form.instructions
486 end]
487 )
488 Registration::Payment::InviteCode::REDIS.expect(
489 :incr,
490 EMPromise.resolve(nil),
491 ["jmp_invite_tries-test"]
492 )
493 Registration::Payment::InviteCode::REDIS.expect(
494 :expire,
495 EMPromise.resolve(nil),
496 ["jmp_invite_tries-test", 60 * 60]
497 )
498 Command::COMMAND_MANAGER.expect(
499 :write,
500 EMPromise.reject(:test_result),
501 [Matching.new do |reply|
502 assert_equal :form, reply.form.type
503 assert_equal "Too many wrong attempts", reply.form.instructions
504 end]
505 )
506 Registration::Payment::InviteCode.new(
507 customer,
508 "+15555550000"
509 ).write.catch { |e| e }
510 end
511 assert_equal :test_result, result
512 assert_mock Command::COMMAND_MANAGER
513 assert_mock Registration::Payment::InviteCode::REDIS
514 end
515 em :test_write_bad_code_over_limit
516 end
517 end
518
519 class FinishTest < Minitest::Test
520 Registration::Finish::REDIS = Minitest::Mock.new
521 BackendSgx::REDIS = Minitest::Mock.new
522
523 def setup
524 @sgx = Minitest::Mock.new(BackendSgx.new("test"))
525 iq = Blather::Stanza::Iq::Command.new
526 iq.from = "test\\40example.com@cheogram.com"
527 @finish = Registration::Finish.new(
528 Customer.new("test", sgx: @sgx),
529 "+15555550000"
530 )
531 end
532
533 def test_write
534 create_order = stub_request(
535 :post,
536 "https://dashboard.bandwidth.com/v1.0/accounts//orders"
537 ).to_return(status: 201, body: <<~RESPONSE)
538 <OrderResponse>
539 <Order>
540 <id>test_order</id>
541 </Order>
542 </OrderResponse>
543 RESPONSE
544 stub_request(
545 :get,
546 "https://dashboard.bandwidth.com/v1.0/accounts//orders/test_order"
547 ).to_return(status: 201, body: <<~RESPONSE)
548 <OrderResponse>
549 <OrderStatus>COMPLETE</OrderStatus>
550 <CompletedNumbers>
551 <TelephoneNumber>
552 <FullNumber>5555550000</FullNumber>
553 </TelephoneNumber>
554 </CompletedNumbers>
555 </OrderResponse>
556 RESPONSE
557 stub_request(
558 :post,
559 "https://api.catapult.inetwork.com/v1/users/catapult_user/phoneNumbers"
560 ).with(
561 body: open(__dir__ + "/data/catapult_import_body.json").read.chomp,
562 headers: {
563 "Authorization" => "Basic Y2F0YXB1bHRfdG9rZW46Y2F0YXB1bHRfc2VjcmV0",
564 "Content-Type" => "application/json"
565 }
566 ).to_return(status: 201)
567 Registration::Finish::REDIS.expect(
568 :set,
569 nil,
570 [
571 "catapult_fwd-+15555550000",
572 "sip:test%40example.com@sip.cheogram.com"
573 ]
574 )
575 BackendSgx::REDIS.expect(
576 :set,
577 nil,
578 ["catapult_fwd_timeout-customer_test@component", 25]
579 )
580 blather = Minitest::Mock.new
581 blather.expect(
582 :<<,
583 nil,
584 [Matching.new do |reply|
585 assert_equal :completed, reply.status
586 assert_equal :info, reply.note_type
587 assert_equal(
588 "Your JMP account has been activated as +15555550000",
589 reply.note.content
590 )
591 end]
592 )
593 execute_command(blather: blather) do
594 @sgx.expect(
595 :register!,
596 EMPromise.resolve(OpenStruct.new(error?: false)),
597 ["+15555550000"]
598 )
599
600 @finish.write
601 end
602 assert_requested create_order
603 assert_mock @sgx
604 assert_mock Registration::Finish::REDIS
605 assert_mock BackendSgx::REDIS
606 assert_mock blather
607 end
608 em :test_write
609
610 def test_write_tn_fail
611 create_order = stub_request(
612 :post,
613 "https://dashboard.bandwidth.com/v1.0/accounts//orders"
614 ).to_return(status: 201, body: <<~RESPONSE)
615 <OrderResponse>
616 <Order>
617 <id>test_order</id>
618 </Order>
619 </OrderResponse>
620 RESPONSE
621 stub_request(
622 :get,
623 "https://dashboard.bandwidth.com/v1.0/accounts//orders/test_order"
624 ).to_return(status: 201, body: <<~RESPONSE)
625 <OrderResponse>
626 <OrderStatus>FAILED</OrderStatus>
627 </OrderResponse>
628 RESPONSE
629 blather = Minitest::Mock.new
630 blather.expect(
631 :<<,
632 nil,
633 [Matching.new do |reply|
634 assert_equal :completed, reply.status
635 assert_equal :error, reply.note_type
636 assert_equal(
637 "The JMP number +15555550000 is no longer available, " \
638 "please visit https://jmp.chat and choose another.",
639 reply.note.content
640 )
641 end]
642 )
643 execute_command(blather: blather) { @finish.write }
644 assert_requested create_order
645 assert_mock blather
646 end
647 em :test_write_tn_fail
648 end
649end