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