sms_safe 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,240 @@
1
+ require_relative "test_helper"
2
+
3
+ class InterceptorTest < MiniTest::Test
4
+ context "With a Base Interceptor" do
5
+ setup do
6
+ @interceptor = SmsSafe::Interceptor.new
7
+ @message = SmsSafe::Message.new(from: EXTERNAL_PHONE_NUMBERS.first, to: EXTERNAL_PHONE_NUMBERS.first, text: "Foo")
8
+ end
9
+
10
+ should "raise an exception if calling convert_message" do
11
+ assert_raises(RuntimeError) do
12
+ @interceptor.convert_message(@message)
13
+ end
14
+ end
15
+
16
+ should "raise an exception if calling redirect" do
17
+ assert_raises(RuntimeError) do
18
+ @interceptor.redirect(@message)
19
+ end
20
+ end
21
+ end
22
+
23
+ context "With a Test Interceptor" do
24
+ setup do
25
+ @interceptor = TestInterceptor.new
26
+
27
+ SmsSafe.configure do |config|
28
+ config.internal_phone_numbers = INTERNAL_PHONE_NUMBERS
29
+ config.intercept_mechanism = :redirect
30
+ config.redirect_target = DEFAULT_INTERNAL_PHONE_NUMBER
31
+ end
32
+
33
+ @internal_message = SmsSafe::Message.new(from: INTERNAL_PHONE_NUMBERS.first, to: INTERNAL_PHONE_NUMBERS.last, text: "Foo") # Doesn't get intercepted
34
+ @external_message = SmsSafe::Message.new(from: INTERNAL_PHONE_NUMBERS.first, to: EXTERNAL_PHONE_NUMBERS.last, text: "Bar") # Gets intercepted
35
+ end
36
+
37
+ context "intercepting by String" do
38
+ setup do
39
+ SmsSafe.configure { |config| config.internal_phone_numbers = DEFAULT_INTERNAL_PHONE_NUMBER }
40
+ end
41
+
42
+ should "choose to intercept message for non-matching numbers" do
43
+ check_interception_rules(@interceptor, EXTERNAL_PHONE_NUMBERS, true)
44
+ end
45
+
46
+ should "not choose to intercept message for internal number" do
47
+ check_interception_rules(@interceptor, [DEFAULT_INTERNAL_PHONE_NUMBER], false)
48
+ end
49
+ end
50
+
51
+ context "intercepting by Regex" do
52
+ setup do
53
+ SmsSafe.configure { |config| config.internal_phone_numbers = INTERNAL_PHONE_NUMBERS_REGEX }
54
+ end
55
+
56
+ should "choose to intercept message for non-matching number" do
57
+ check_interception_rules(@interceptor, EXTERNAL_PHONE_NUMBERS, true)
58
+ end
59
+
60
+ should "not choose to intercept message for internal number" do
61
+ check_interception_rules(@interceptor, INTERNAL_PHONE_NUMBERS, false)
62
+ end
63
+ end
64
+
65
+ context "intercepting by Proc" do
66
+ setup do
67
+ SmsSafe.configure { |config| config.internal_phone_numbers = INTERNAL_PHONE_NUMBERS_PROC }
68
+ end
69
+
70
+ should "choose to intercept message for non-matching number" do
71
+ check_interception_rules(@interceptor, EXTERNAL_PHONE_NUMBERS, true)
72
+ end
73
+
74
+ should "not choose to intercept message for internal number" do
75
+ check_interception_rules(@interceptor, INTERNAL_PHONE_NUMBERS, false)
76
+ end
77
+ end
78
+
79
+ context "intercepting by Mixture of methods" do
80
+ setup do
81
+ SmsSafe.configure { |config| config.internal_phone_numbers = [DEFAULT_INTERNAL_PHONE_NUMBER, INTERNAL_PHONE_NUMBERS_REGEX, INTERNAL_PHONE_NUMBERS_PROC] }
82
+ end
83
+
84
+ should "choose to intercept message for non-matching number" do
85
+ check_interception_rules(@interceptor, EXTERNAL_PHONE_NUMBERS, true)
86
+ end
87
+
88
+ should "not choose to intercept message for internal number" do
89
+ check_interception_rules(@interceptor, INTERNAL_PHONE_NUMBERS, false)
90
+ end
91
+ end
92
+
93
+ context "intercepting by Invalid Comparison Method" do
94
+ setup do
95
+ SmsSafe.configure { |config| config.internal_phone_numbers = 5 } # An Integer is not a valid rule for comparison
96
+ end
97
+
98
+ should "raise exception" do
99
+ assert_raises(SmsSafe::InvalidConfigSettingError) do
100
+ check_interception_rules(@interceptor, INTERNAL_PHONE_NUMBERS, false)
101
+ end
102
+ end
103
+ end
104
+
105
+ context "intercepting by Redirecting" do
106
+ # The logic inside redirect is tested within each of the interceptors, not here
107
+ should "return an intercepted message if intercepting" do
108
+ original_message = @external_message.clone
109
+ result = @interceptor.process_message(@external_message)
110
+ refute_nil result
111
+ assert_equal SmsSafe::Message, result.class
112
+ assert_operator original_message.text.length, :<, result.text.length # Message length must have increased
113
+ assert_match original_message.text, result.text # New message must include the original one
114
+ refute_equal original_message.to, result.to # Recipient must have changed
115
+ assert_equal SmsSafe.configuration.redirect_target, result.to # Recipient must be redirect target
116
+ end
117
+
118
+ should "return an identical message if not intercepting" do
119
+ process_and_assert_identical_message(@interceptor, @internal_message)
120
+ end
121
+ end
122
+
123
+ context "intercepting by Emailing" do
124
+ setup do
125
+ SmsSafe.configure do |config|
126
+ config.intercept_mechanism = :email
127
+ config.email_target = 'blah@blah.com'
128
+ end
129
+ end
130
+
131
+ should "send an email and return nil if intercepting" do
132
+ original_message = @external_message.clone
133
+ assert_difference "Mail::TestMailer.deliveries.length", +1 do
134
+ result = @interceptor.process_message(@external_message)
135
+ assert_nil result
136
+ end
137
+
138
+ mail = Mail::TestMailer.deliveries.last
139
+
140
+ assert have_sent_email.from('blah@blah.com').matches?(mail)
141
+ assert have_sent_email.to('blah@blah.com').matches?(mail)
142
+ assert_match original_message.text, mail.body.to_s # Email must contain original SMS text, from and to
143
+ assert_match original_message.from, mail.body.to_s
144
+ assert_match original_message.to, mail.body.to_s
145
+ end
146
+
147
+ should "return an identical message if not intercepting" do
148
+ process_and_assert_identical_message(@interceptor, @internal_message)
149
+ end
150
+ end
151
+
152
+ context "intercepting by Discarding" do
153
+ setup do
154
+ SmsSafe.configure do |config|
155
+ config.intercept_mechanism = :discard
156
+ config.discard_delay = 0
157
+ end
158
+ end
159
+
160
+ should "return immediately and return nil if intercepting without delay" do
161
+ time_to_run = Benchmark.realtime do
162
+ result = @interceptor.process_message(@external_message)
163
+ assert_nil result
164
+ end
165
+ assert_operator 20, :>=, time_to_run * 1000 # Must take less than 20ms (arbitrary number picked to show there's no delay)
166
+ end
167
+
168
+ context "with delay" do
169
+ setup do
170
+ SmsSafe.configure { |config| config.discard_delay = 100 } # Delay by 100ms
171
+ end
172
+ should "delay and return nil if intercepting with delay" do
173
+ time_to_run = Benchmark.realtime do
174
+ result = @interceptor.process_message(@external_message)
175
+ assert_nil result
176
+ end
177
+ assert_operator 100, :<=, time_to_run * 1000 # Must take at least 100ms
178
+ end
179
+ end
180
+
181
+ should "return an identical message if not intercepting" do
182
+ process_and_assert_identical_message(@interceptor, @internal_message)
183
+ end
184
+ end
185
+
186
+ context "intercepting by Invalid Mechanism" do
187
+ setup do
188
+ SmsSafe.configure { |config| config.intercept_mechanism = :invalid }
189
+ end
190
+
191
+ should "raise an exception if intercepting" do
192
+ assert_raises(SmsSafe::InvalidConfigSettingError) do
193
+ @interceptor.process_message(@external_message)
194
+ end
195
+ end
196
+ end
197
+
198
+ context "resolving target phone number by Proc" do
199
+ setup do
200
+ SmsSafe.configure { |config| config.redirect_target = Proc.new { |m| "#{m.to}#123" } }
201
+ end
202
+ should "redirect to the appropriate phone number" do
203
+ result = @interceptor.redirect_phone_number(@external_message)
204
+ assert_equal @external_message.to + "#123", result
205
+ end
206
+ end
207
+
208
+ context "resolving target phone number by Invalid Method" do
209
+ setup do
210
+ SmsSafe.configure { |config| config.redirect_target = /5/ } # A regex is not a valid target
211
+ end
212
+ should "raise an exception if redirecting" do
213
+ assert_raises(SmsSafe::InvalidConfigSettingError) do
214
+ @interceptor.redirect_phone_number(@external_message)
215
+ end
216
+ end
217
+ end
218
+
219
+ context "resolving target email by Proc" do
220
+ setup do
221
+ SmsSafe.configure { |config| config.email_target = Proc.new { |m| "#{m.to}@blah.com" } }
222
+ end
223
+ should "email to the appropriate address" do
224
+ result = @interceptor.email_recipient(@external_message)
225
+ assert_equal @external_message.to + "@blah.com", result
226
+ end
227
+ end
228
+
229
+ context "resolving target email by Invalid Method" do
230
+ setup do
231
+ SmsSafe.configure { |config| config.email_target = /5/ } # A regex is not a valid target
232
+ end
233
+ should "raise an exception if redirecting" do
234
+ assert_raises(SmsSafe::InvalidConfigSettingError) do
235
+ @interceptor.email_recipient(@external_message)
236
+ end
237
+ end
238
+ end
239
+ end # context "With a base Interceptor"
240
+ end
@@ -0,0 +1,76 @@
1
+ require_relative "../test_helper"
2
+ require "action_texter"
3
+
4
+ class ActionTexterTest < MiniTest::Test
5
+
6
+ # Check that a message that got redirected is being sent to the right recipient, with changed message,
7
+ # but keeps everything else intact
8
+ def check_redirected_message(original_message, redirected_message)
9
+ assert_equal ActionTexter::Message, redirected_message.class # Check that we are returning the original class
10
+ assert_equal original_message.from, redirected_message.from # With intact from
11
+ assert_equal SmsSafe.configuration.redirect_target, redirected_message.to # New recipient
12
+ assert_operator original_message.text.length, :<, redirected_message.text.length # Modified text
13
+ assert_match original_message.text, redirected_message.text # that includes the original message
14
+ assert_equal original_message.reference, redirected_message.reference # and with intact extra attributes
15
+ end
16
+
17
+ context "With an ActionTexter interceptor" do
18
+ setup do
19
+ SmsSafe.configure do |config|
20
+ config.internal_phone_numbers = INTERNAL_PHONE_NUMBERS
21
+ config.intercept_mechanism = :redirect
22
+ config.redirect_target = DEFAULT_INTERNAL_PHONE_NUMBER
23
+ end
24
+
25
+ @interceptor = SmsSafe::Interceptors::ActionTexter.new
26
+ @original_message = ActionTexter::Message.new(from: DEFAULT_INTERNAL_PHONE_NUMBER, to: EXTERNAL_PHONE_NUMBERS.first, text: "Foo", reference: "message_reference-1234")
27
+ end
28
+
29
+ should "convert Message" do
30
+ converted_message = @interceptor.convert_message(@original_message.clone)
31
+
32
+ assert_equal SmsSafe::Message, converted_message.class # Check that we converted into our internal class
33
+ assert_equal @original_message.from, converted_message.from # Check that the important attributes are conserved
34
+ assert_equal @original_message.to, converted_message.to
35
+ assert_equal @original_message.text, converted_message.text
36
+ assert_equal @original_message.instance_variables_hash, converted_message.original_message.instance_variables_hash # Check that the original messages with its extra attributes are conserved
37
+ assert_equal @original_message.reference, converted_message.original_message.reference
38
+ end
39
+
40
+ should "modify message recipient and text when redirecting" do
41
+ converted_message = @interceptor.convert_message(@original_message.clone)
42
+ redirected_message = @interceptor.redirect(converted_message)
43
+ check_redirected_message(@original_message, redirected_message)
44
+ end
45
+
46
+ context "With a redirect intercept" do
47
+ should "return modified message if intercepting" do
48
+ result = @interceptor.delivering_sms(@original_message.clone)
49
+ check_redirected_message(@original_message, result)
50
+ end
51
+ should "return original message if not intercepting" do
52
+ @original_message.to = DEFAULT_INTERNAL_PHONE_NUMBER
53
+ message = @original_message.clone
54
+ result = @interceptor.delivering_sms(message)
55
+
56
+ refute_nil result
57
+ assert_equal @original_message.class, result.class # We get back the correct class,
58
+ assert_equal message.object_id, result.object_id # the same exact object we passed in
59
+ assert_equal @original_message.instance_variables_hash, result.instance_variables_hash # with the same attributes we always had (need to check this since it could be returning a modified object)
60
+ end
61
+ end
62
+
63
+ context "With a discard intercept" do
64
+ setup do
65
+ SmsSafe.configure do |config|
66
+ config.intercept_mechanism = :discard
67
+ config.discard_delay = 0
68
+ end
69
+ end
70
+ should "return nil if intercepting a message" do
71
+ result = @interceptor.delivering_sms(@original_message.clone)
72
+ assert_nil result
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,73 @@
1
+ require_relative "../test_helper"
2
+ require "nexmo"
3
+
4
+ class NexmoTest < MiniTest::Test
5
+
6
+ # Check that a message that got redirected is being sent to the right recipient, with changed message,
7
+ # but keeps everything else intact
8
+ def check_redirected_message(original_message, redirected_message)
9
+ assert_equal Hash, redirected_message.class # Check that we are returning the original class
10
+ assert_equal original_message[:from], redirected_message[:from] # With intact from
11
+ assert_equal SmsSafe.configuration.redirect_target, redirected_message[:to] # New recipient
12
+ assert_operator original_message[:text].length, :<, redirected_message[:text].length # Modified text
13
+ assert_match original_message[:text], redirected_message[:text] # that includes the original message
14
+ end
15
+
16
+ context "With a Nexmo interceptor" do
17
+ setup do
18
+ SmsSafe.configure do |config|
19
+ config.internal_phone_numbers = INTERNAL_PHONE_NUMBERS
20
+ config.intercept_mechanism = :redirect
21
+ config.redirect_target = DEFAULT_INTERNAL_PHONE_NUMBER
22
+ end
23
+
24
+ @interceptor = SmsSafe::Interceptors::Nexmo.new
25
+ @original_message = { from: DEFAULT_INTERNAL_PHONE_NUMBER, to: EXTERNAL_PHONE_NUMBERS.first, text: 'Foo' }
26
+ end
27
+
28
+ should "convert Message" do
29
+ converted_message = @interceptor.convert_message(@original_message.clone)
30
+
31
+ assert_equal SmsSafe::Message, converted_message.class # Check that we converted into our internal class
32
+ assert_equal @original_message[:from], converted_message.from # Check that the important attributes are conserved
33
+ assert_equal @original_message[:to], converted_message.to
34
+ assert_equal @original_message[:text], converted_message.text
35
+ assert_equal @original_message, converted_message.original_message # Check that the original messages with its extra attributes are conserved
36
+ end
37
+
38
+ should "modify message recipient and text when redirecting" do
39
+ converted_message = @interceptor.convert_message(@original_message.clone)
40
+ redirected_message = @interceptor.redirect(converted_message)
41
+ check_redirected_message(@original_message, redirected_message)
42
+ end
43
+
44
+ context "With a redirect intercept" do
45
+ should "return modified message if intercepting" do
46
+ result = @interceptor.process_message(@original_message.clone)
47
+ check_redirected_message(@original_message, result)
48
+ end
49
+ should "return original message if not intercepting" do
50
+ @original_message[:to] = DEFAULT_INTERNAL_PHONE_NUMBER
51
+ message = @original_message.clone
52
+ result = @interceptor.process_message(message)
53
+
54
+ refute_nil result
55
+ assert_equal @original_message.class, result.class # We get back the correct class,
56
+ assert_equal message.object_id, result.object_id # the same exact object we passed in
57
+ assert_equal @original_message, result # with the same attributes we always had (need to check this since it could be returning a modified object)
58
+ end
59
+ end
60
+ context "With a discard intercept" do
61
+ setup do
62
+ SmsSafe.configure do |config|
63
+ config.intercept_mechanism = :discard
64
+ config.discard_delay = 0
65
+ end
66
+ end
67
+ should "return nil if intercepting a message" do
68
+ result = @interceptor.process_message(@original_message.clone)
69
+ assert_nil result
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,72 @@
1
+ require_relative "../test_helper"
2
+ require "twilio-ruby"
3
+
4
+ class TwilioTest < MiniTest::Test
5
+ # Check that a message that got redirected is being sent to the right recipient, with changed message,
6
+ # but keeps everything else intact
7
+ def check_redirected_message(original_message, redirected_message)
8
+ assert_equal Hash, redirected_message.class # Check that we are returning the original class
9
+ assert_equal original_message[:from], redirected_message[:from] # With intact from
10
+ assert_equal SmsSafe.configuration.redirect_target, redirected_message[:to] # New recipient
11
+ assert_operator original_message[:body].length, :<, redirected_message[:body].length # Modified body
12
+ assert_match original_message[:body], redirected_message[:body] # that includes the original message
13
+ end
14
+
15
+ context "With a Twilio interceptor" do
16
+ setup do
17
+ SmsSafe.configure do |config|
18
+ config.internal_phone_numbers = INTERNAL_PHONE_NUMBERS
19
+ config.intercept_mechanism = :redirect
20
+ config.redirect_target = DEFAULT_INTERNAL_PHONE_NUMBER
21
+ end
22
+
23
+ @interceptor = SmsSafe::Interceptors::Twilio.new
24
+ @original_message = { from: DEFAULT_INTERNAL_PHONE_NUMBER, to: EXTERNAL_PHONE_NUMBERS.first, body: 'Foo' }
25
+ end
26
+
27
+ should "convert Message" do
28
+ converted_message = @interceptor.convert_message(@original_message.clone)
29
+
30
+ assert_equal SmsSafe::Message, converted_message.class # Check that we converted into our internal class
31
+ assert_equal @original_message[:from], converted_message.from # Check that the important attributes are conserved
32
+ assert_equal @original_message[:to], converted_message.to
33
+ assert_equal @original_message[:body], converted_message.text
34
+ assert_equal @original_message, converted_message.original_message # Check that the original messages with its extra attributes are conserved
35
+ end
36
+
37
+ should "modify message recipient and text when redirecting" do
38
+ converted_message = @interceptor.convert_message(@original_message.clone)
39
+ redirected_message = @interceptor.redirect(converted_message)
40
+ check_redirected_message(@original_message, redirected_message)
41
+ end
42
+
43
+ context "With a redirect intercept" do
44
+ should "return modified message if intercepting" do
45
+ result = @interceptor.process_message(@original_message.clone)
46
+ check_redirected_message(@original_message, result)
47
+ end
48
+ should "return original message if not intercepting" do
49
+ @original_message[:to] = DEFAULT_INTERNAL_PHONE_NUMBER
50
+ message = @original_message.clone
51
+ result = @interceptor.process_message(message)
52
+
53
+ refute_nil result
54
+ assert_equal @original_message.class, result.class # We get back the correct class,
55
+ assert_equal message.object_id, result.object_id # the same exact object we passed in
56
+ assert_equal @original_message, result # with the same attributes we always had (need to check this since it could be returning a modified object)
57
+ end
58
+ end
59
+ context "With a discard intercept" do
60
+ setup do
61
+ SmsSafe.configure do |config|
62
+ config.intercept_mechanism = :discard
63
+ config.discard_delay = 0
64
+ end
65
+ end
66
+ should "return nil if intercepting a message" do
67
+ result = @interceptor.process_message(@original_message.clone)
68
+ assert_nil result
69
+ end
70
+ end
71
+ end
72
+ end