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