test_component.rb

  1# frozen_string_literal: true
  2
  3require "test_helper"
  4require_relative "../sgx-bwmsgsv2"
  5
  6def panic(e)
  7	$panic = e
  8end
  9
 10class ComponentTest < Minitest::Test
 11	def setup
 12		SGXbwmsgsv2.instance_variable_set(:@written, [])
 13
 14		def SGXbwmsgsv2.write_to_stream(s)
 15			@written ||= []
 16			@written << s
 17		end
 18
 19		REDIS.reset!
 20		REDIS.set("catapult_jid-", "HERE")
 21		REDIS.set("catapult_jid-+15550000000", "test@example.com")
 22		REDIS.set("catapult_cred-test@example.com", [
 23			'account', 'user', 'password', '+15550000000'
 24		])
 25	end
 26
 27	def written
 28		SGXbwmsgsv2.instance_variable_get(:@written)
 29	end
 30
 31	def xmpp_error_name(error)
 32		error.find_first(
 33			"child::*[name()!='text']",
 34			Blather::StanzaError::STANZA_ERR_NS
 35		).element_name
 36	end
 37
 38	def xmpp_error_text(error)
 39		error.find_first("ns:text", ns: Blather::StanzaError::STANZA_ERR_NS)&.text
 40	end
 41
 42	def process_stanza(s)
 43		SGXbwmsgsv2.send(:client).receive_data(s)
 44		raise $panic if $panic
 45	end
 46
 47	def test_message_unregistered
 48		m = Blather::Stanza::Message.new("+15551234567@component", "a"*4096)
 49		m.from = "unknown@example.com"
 50		process_stanza(m)
 51
 52		assert_equal 1, written.length
 53
 54		stanza = Blather::XMPPNode.parse(written.first.to_xml)
 55		assert stanza.error?
 56		error = stanza.find_first("error")
 57		assert_equal "auth", error["type"]
 58		assert_equal "registration-required", xmpp_error_name(error)
 59	end
 60	em :test_message_unregistered
 61
 62	def test_message_too_long
 63		req = stub_request(
 64			:post,
 65			"https://messaging.bandwidth.com/api/v2/users/account/messages"
 66		).with(body: {
 67			from: "+15550000000",
 68			to: "+15551234567",
 69			text: "a"*4096,
 70			applicationId: nil,
 71			tag: " "
 72		}).to_return(status: 400, body: JSON.dump(
 73			description: "Bad text.",
 74			fieldErrors: [{ description: "4096 not allowed" }]
 75		))
 76
 77		m = Blather::Stanza::Message.new("+15551234567@component", "a"*4096)
 78		m.from = "test@example.com"
 79		process_stanza(m)
 80
 81		assert_requested req
 82		assert_equal 1, written.length
 83
 84		stanza = Blather::XMPPNode.parse(written.first.to_xml)
 85		assert stanza.error?
 86		error = stanza.find_first("error")
 87		assert_equal "cancel", error["type"]
 88		assert_equal "internal-server-error", xmpp_error_name(error)
 89		assert_equal "Bad text. 4096 not allowed", xmpp_error_text(error)
 90	end
 91	em :test_message_too_long
 92
 93	def test_message_to_component_not_group
 94		m = Blather::Stanza::Message.new("component", "a"*4096)
 95		m.from = "test@example.com"
 96		process_stanza(m)
 97
 98		assert_equal 1, written.length
 99
100		stanza = Blather::XMPPNode.parse(written.first.to_xml)
101		assert stanza.error?
102		error = stanza.find_first("error")
103		assert_equal "cancel", error["type"]
104		assert_equal "item-not-found", xmpp_error_name(error)
105	end
106	em :test_message_to_component_not_group
107
108	def test_message_to_invalid_num
109		m = Blather::Stanza::Message.new("123@component", "a"*4096)
110		m.from = "test@example.com"
111		process_stanza(m)
112
113		assert_equal 1, written.length
114
115		stanza = Blather::XMPPNode.parse(written.first.to_xml)
116		assert stanza.error?
117		error = stanza.find_first("error")
118		assert_equal "cancel", error["type"]
119		assert_equal "item-not-found", xmpp_error_name(error)
120	end
121	em :test_message_to_invalid_num
122
123	def test_message_to_anonymous
124		m = Blather::Stanza::Message.new(
125			"1;phone-context=anonymous.phone-context.soprani.ca@component",
126			"a"*4096
127		)
128		m.from = "test@example.com"
129		process_stanza(m)
130
131		assert_equal 1, written.length
132
133		stanza = Blather::XMPPNode.parse(written.first.to_xml)
134		assert stanza.error?
135		error = stanza.find_first("error")
136		assert_equal "cancel", error["type"]
137		assert_equal "gone", xmpp_error_name(error)
138	end
139	em :test_message_to_anonymous
140
141	def test_blank_message
142		m = Blather::Stanza::Message.new("+15551234567@component", " ")
143		m.from = "test@example.com"
144		process_stanza(m)
145
146		assert_equal 1, written.length
147
148		stanza = Blather::XMPPNode.parse(written.first.to_xml)
149		assert stanza.error?
150		error = stanza.find_first("error")
151		assert_equal "modify", error["type"]
152		assert_equal "policy-violation", xmpp_error_name(error)
153	end
154	em :test_blank_message
155
156	def test_ibr_bad_tel
157		iq = Blather::Stanza::Iq::IBR.new(:set, "component")
158		iq.from = "newuser@example.com"
159		iq.phone = "5551234567"
160		process_stanza(iq)
161
162		assert_equal 1, written.length
163
164		stanza = Blather::XMPPNode.parse(written.first.to_xml)
165		assert stanza.error?
166		error = stanza.find_first("error")
167		assert_equal "cancel", error["type"]
168		assert_equal "item-not-found", xmpp_error_name(error)
169	end
170	em :test_ibr_bad_tel
171
172	def test_ibr_bad_creds
173		stub_request(
174			:get,
175			"https://messaging.bandwidth.com/api/v2/users/acct/media"
176		).with(basic_auth: ["user", "pw"]).to_return(status: 401)
177
178		iq = Blather::Stanza::Iq::IBR.new(:set, "component")
179		iq.from = "newuser@example.com"
180		iq.phone = "+15551234567"
181		iq.nick = "acct"
182		iq.username = "user"
183		iq.password = "pw"
184		process_stanza(iq)
185
186		assert_equal 1, written.length
187
188		stanza = Blather::XMPPNode.parse(written.first.to_xml)
189		assert stanza.error?
190		error = stanza.find_first("error")
191		assert_equal "auth", error["type"]
192		assert_equal "not-authorized", xmpp_error_name(error)
193	end
194	em :test_ibr_bad_creds
195
196	def test_ibr_number_not_found
197		stub_request(
198			:get,
199			"https://messaging.bandwidth.com/api/v2/users/acct/media"
200		).with(basic_auth: ["user", "pw"]).to_return(status: 404)
201
202		iq = Blather::Stanza::Iq::IBR.new(:set, "component")
203		iq.from = "newuser@example.com"
204		iq.phone = "+15551234567"
205		iq.nick = "acct"
206		iq.username = "user"
207		iq.password = "pw"
208		process_stanza(iq)
209
210		assert_equal 1, written.length
211
212		stanza = Blather::XMPPNode.parse(written.first.to_xml)
213		assert stanza.error?
214		error = stanza.find_first("error")
215		assert_equal "cancel", error["type"]
216		assert_equal "item-not-found", xmpp_error_name(error)
217	end
218	em :test_ibr_number_not_found
219
220	def test_ibr_other_error
221		stub_request(
222			:get,
223			"https://messaging.bandwidth.com/api/v2/users/acct/media"
224		).with(basic_auth: ["user", "pw"]).to_return(status: 400)
225
226		iq = Blather::Stanza::Iq::IBR.new(:set, "component")
227		iq.from = "newuser@example.com"
228		iq.phone = "+15551234567"
229		iq.nick = "acct"
230		iq.username = "user"
231		iq.password = "pw"
232		process_stanza(iq)
233
234		assert_equal 1, written.length
235
236		stanza = Blather::XMPPNode.parse(written.first.to_xml)
237		assert stanza.error?
238		error = stanza.find_first("error")
239		assert_equal "modify", error["type"]
240		assert_equal "not-acceptable", xmpp_error_name(error)
241	end
242	em :test_ibr_other_error
243
244	def test_ibr_new
245		stub_request(
246			:get,
247			"https://messaging.bandwidth.com/api/v2/users/acct/media"
248		).with(basic_auth: ["user", "pw"]).to_return(status: 200, body: "[]")
249
250		iq = Blather::Stanza::Iq::IBR.new(:set, "component")
251		iq.from = "test9@example.com"
252		iq.phone = "+15550000009"
253		iq.nick = "acct"
254		iq.username = "user"
255		iq.password = "pw"
256		process_stanza(iq)
257
258		assert_equal 1, written.length
259
260		stanza = Blather::XMPPNode.parse(written.first.to_xml)
261		refute stanza.error?
262		assert_equal(
263			["acct", "user", "pw", "+15550000009"],
264			REDIS.get("catapult_cred-test9@example.com").sync
265		)
266		assert_equal "test9@example.com", REDIS.get("catapult_jid-+15550000009").sync
267		assert REDIS.get("catapult_jid-").sync
268	end
269	em :test_ibr_new
270
271	def test_ibr_update
272		stub_request(
273			:get,
274			"https://messaging.bandwidth.com/api/v2/users/acct/media"
275		).with(basic_auth: ["user", "pw"]).to_return(status: 200, body: "[]")
276
277		iq = Blather::Stanza::Iq::IBR.new(:set, "component")
278		iq.from = "test@example.com"
279		iq.phone = "+15550000009"
280		iq.nick = "acct"
281		iq.username = "user"
282		iq.password = "pw"
283		process_stanza(iq)
284
285		assert_equal 1, written.length
286
287		stanza = Blather::XMPPNode.parse(written.first.to_xml)
288		refute stanza.error?
289		assert_equal(
290			["acct", "user", "pw", "+15550000009"],
291			REDIS.get("catapult_cred-test@example.com").sync
292		)
293		assert_equal "test@example.com", REDIS.get("catapult_jid-+15550000009").sync
294		refute REDIS.get("catapult_jid-+15550000000").sync
295	end
296	em :test_ibr_update
297
298	def test_ibr_conflict
299		stub_request(
300			:get,
301			"https://messaging.bandwidth.com/api/v2/users/acct/media"
302		).with(basic_auth: ["user", "pw"]).to_return(status: 200, body: "[]")
303
304		iq = Blather::Stanza::Iq::IBR.new(:set, "component")
305		iq.from = "test2@example.com"
306		iq.phone = "+15550000000"
307		iq.nick = "acct"
308		iq.username = "user"
309		iq.password = "pw"
310		process_stanza(iq)
311
312		assert_equal 1, written.length
313
314		stanza = Blather::XMPPNode.parse(written.first.to_xml)
315		assert stanza.error?
316		error = stanza.find_first("error")
317		assert_equal "cancel", error["type"]
318		assert_equal "conflict", xmpp_error_name(error)
319		assert_equal(
320			"Another user exists for +15550000000",
321			xmpp_error_text(error)
322		)
323	end
324	em :test_ibr_conflict
325
326	def test_ibr_remove
327		iq = Blather::Stanza::Iq::IBR.new(:set, "component")
328		iq.from = "test@example.com"
329		iq.remove!
330		process_stanza(iq)
331
332		refute REDIS.get("catapult_cred-test@example.com").sync
333
334		assert_equal 1, written.length
335
336		stanza = Blather::XMPPNode.parse(written.first.to_xml)
337		assert stanza.result?
338	end
339	em :test_ibr_remove
340
341	def test_ibr_form
342		stub_request(
343			:get,
344			"https://messaging.bandwidth.com/api/v2/users/acct/media"
345		).with(basic_auth: ["user", "pw"]).to_return(status: 200, body: "[]")
346
347		iq = Blather::Stanza::Iq::IBR.new(:set, "component")
348		iq.from = "formuser@example.com"
349		form = Blather::Stanza::X.find_or_create(iq.query)
350		form.fields = [
351			{
352				var: "nick",
353				value: "acct"
354			},
355			{
356				var: "username",
357				value: "user"
358			},
359			{
360				var: "password",
361				value: "pw"
362			},
363			{
364				var: "phone",
365				value: "+15551234567"
366			}
367		]
368		process_stanza(iq)
369
370		assert_equal(
371			["acct", "user", "pw", "+15551234567"],
372			REDIS.get("catapult_cred-formuser@example.com").sync
373		)
374
375		assert_equal(
376			"formuser@example.com",
377			REDIS.get("catapult_jid-+15551234567").sync
378		)
379
380		assert_equal 1, written.length
381		stanza = Blather::XMPPNode.parse(written.first.to_xml)
382		assert stanza.result?
383	end
384	em :test_ibr_form
385
386	def test_ibr_get_form_registered
387		iq = Blather::Stanza::Iq::IBR.new(:get, "component")
388		iq.from = "test@example.com"
389		process_stanza(iq)
390
391		assert_equal 1, written.length
392		stanza = Blather::XMPPNode.parse(written.first.to_xml)
393		assert stanza.result?
394		assert stanza.registered?
395		assert_equal(
396			["nick", "username", "password", "phone"],
397			stanza.form.fields.map(&:var)
398		)
399		assert stanza.instructions
400		assert stanza.nick
401		assert stanza.username
402		assert stanza.password
403		assert stanza.phone
404		refute stanza.email
405	end
406	em :test_ibr_get_form_registered
407
408	def test_port_out_pin
409		iq = Blather::Stanza::Iq::Command.new(:set, 'component').tap do |iq|
410			iq.from = 'test@example.com'
411			iq.node = 'set-port-out-pin'
412			iq.sessionid = 'test-session-123'
413			iq.action = :complete
414			iq.form.type = :submit
415			iq.form.fields = [
416				{
417					var: 'pin',
418					value: '1234'
419				},
420				{
421					var: 'confirm_pin',
422					value: '1234'
423				}
424			]
425		end
426
427		BandwidthIris::TnOptions.stub :create_tn_option_order,
428			->(client, data) { {order_id: 'test-order-123', processing_status: 'RECEIVED', error_list: {}} } do
429			BandwidthIris::TnOptions.stub :get_tn_option_order,
430				->(client, order_id) { {order_id: order_id, order_status: 'COMPLETE', error_list: {}} } do
431
432				process_stanza(iq)
433
434				assert_equal 1, written.length
435
436				stanza = Blather::XMPPNode.parse(written.first.to_xml)
437				refute stanza.error?
438			end
439		end
440	end
441	em :test_port_out_pin
442
443	def test_port_out_pin_mismatch
444		iq = Blather::Stanza::Iq::Command.new(:set, 'component').tap do |iq|
445			iq.from = 'test@example.com'
446			iq.node = 'set-port-out-pin'
447			iq.sessionid = 'test-session-mismatch'
448			iq.action = :complete
449			iq.form.type = :submit
450			iq.form.fields = [
451				{
452					var: 'pin',
453					value: '1234'
454				},
455				{
456					var: 'confirm_pin',
457					value: '5678'
458				}
459			]
460		end
461
462		process_stanza(iq)
463
464		assert_equal 1, written.length
465
466		stanza = Blather::XMPPNode.parse(written.first.to_xml)
467		assert_equal :error, stanza.type
468		error = stanza.find_first("error")
469		assert_equal "modify", error["type"]
470		assert_equal "bad-request", xmpp_error_name(error)
471		assert_equal "PIN confirmation does not match", xmpp_error_text(error)
472	end
473	em :test_port_out_pin_mismatch
474
475	def test_port_out_pin_validation
476		[
477			['123', 'PIN must be 4-10 alphanumeric characters'],
478			['12345678901', 'PIN must be 4-10 alphanumeric characters'],
479			['123!', 'PIN must be 4-10 alphanumeric characters'],
480			['pin with spaces', 'PIN must be 4-10 alphanumeric characters']
481		].each do |invalid_pin, expected_error|
482			iq = Blather::Stanza::Iq::Command.new(:set, 'component').tap do |iq|
483				iq.from = 'test@example.com'
484				iq.node = 'set-port-out-pin'
485				iq.sessionid = "test-session-validation-#{invalid_pin.gsub(/[^a-zA-Z0-9]/, '')}"
486				iq.action = :complete
487				iq.form.type = :submit
488				iq.form.fields = [
489					{
490						var: 'pin',
491						value: invalid_pin
492					},
493					{
494						var: 'confirm_pin',
495						value: invalid_pin
496					}
497				]
498			end
499
500			process_stanza(iq)
501
502			assert_equal 1, written.length, "Failed for PIN: #{invalid_pin}"
503
504			stanza = Blather::XMPPNode.parse(written.first.to_xml)
505			assert_equal :error, stanza.type, "Expected error for PIN: #{invalid_pin}"
506			error = stanza.find_first("error")
507			assert_equal "modify", error["type"]
508			assert_equal "bad-request", xmpp_error_name(error)
509			assert_equal expected_error, xmpp_error_text(error),
510			             "Wrong error message for PIN: #{invalid_pin}"
511
512			SGXbwmsgsv2.instance_variable_set(:@written, [])
513		end
514	end
515	em :test_port_out_pin_validation
516end