sms_safe 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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