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