mollie-sms 0.2.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +104 -0
- data/Rakefile +10 -0
- data/VERSION +1 -1
- data/lib/mollie/sms.rb +201 -21
- data/lib/mollie/sms/test_helper.rb +173 -46
- data/mollie-sms.gemspec +4 -4
- data/rails/init.rb +1 -1
- data/spec/sms_spec.rb +3 -3
- data/spec/test_helper_spec.rb +2 -2
- metadata +7 -7
- data/README +0 -7
data/README.rdoc
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
A Ruby client that allows you to send SMS messages via
|
2
|
+
{http://www.mollie.nl/sms-diensten/sms-gateway Mollie.nl}.
|
3
|
+
|
4
|
+
See {Mollie::SMS} for the API documentation. Or, if you are reading this as
|
5
|
+
plain text, on {http://rdoc.info/projects/Fingertips/Mollie-SMS rdoc.info}.
|
6
|
+
|
7
|
+
See the Mollie.nl API
|
8
|
+
{http://www.mollie.nl/support/documentatie/sms-diensten/sms/http/en documentation}
|
9
|
+
for more info.
|
10
|
+
|
11
|
+
*Note* that it currently only does what we need, for our app, at this point in
|
12
|
+
time. Which means that it connects to the webservice via SSL, and only sends a
|
13
|
+
message to *one* recipient at a time. Finally, it assumes ActiveSupport is
|
14
|
+
available for XML parsing. (A patch that adds a fallback, to REXML, is much
|
15
|
+
appreciated.)
|
16
|
+
|
17
|
+
= Install
|
18
|
+
|
19
|
+
$ gem install mollie-sms
|
20
|
+
|
21
|
+
Or if you have a checkout of the source and have installed Jeweler:
|
22
|
+
|
23
|
+
$ rake install
|
24
|
+
|
25
|
+
= Configuration
|
26
|
+
|
27
|
+
The minimum required settings are:
|
28
|
+
* {Mollie::SMS.username username}
|
29
|
+
* {Mollie::SMS.password password}
|
30
|
+
* {Mollie::SMS.originator originator}
|
31
|
+
|
32
|
+
For example, a Rails initializer might look like:
|
33
|
+
|
34
|
+
module Mollie
|
35
|
+
SMS.username = 'Fingertips'
|
36
|
+
SMS.password = 'secret'
|
37
|
+
SMS.originator = 'fngtps.nl'
|
38
|
+
end
|
39
|
+
|
40
|
+
= Examples
|
41
|
+
|
42
|
+
== Normal usage
|
43
|
+
|
44
|
+
require 'mollie/sms'
|
45
|
+
|
46
|
+
sms = Mollie::SMS.new('+31681664814', 'You have won a bowl of chicken noodle soup!')
|
47
|
+
=> #<Mollie::SMS from: <fngtps.nl> to: <+31681664814> body: "You have won a bowl of chicken noodle soup!">
|
48
|
+
|
49
|
+
response = sms.deliver # => #<Mollie::SMS::Response succeeded (10) `Message successfully sent.'>
|
50
|
+
|
51
|
+
response.success? # => true
|
52
|
+
response.result_code # => 10
|
53
|
+
response.message # => "Message successfully sent."
|
54
|
+
|
55
|
+
== Test usage
|
56
|
+
|
57
|
+
require 'mollie/sms'
|
58
|
+
require 'mollie/sms/test_helper'
|
59
|
+
|
60
|
+
Mollie::SMS.http_failure!
|
61
|
+
|
62
|
+
response = sms.deliver # => #<Mollie::SMS::Response failed (400) `[HTTP: 400] Bad request'>
|
63
|
+
response.success? # => false
|
64
|
+
response.result_code # => 400
|
65
|
+
response.message # => "[HTTP: 400] Bad request"
|
66
|
+
|
67
|
+
Mollie::SMS.gateway_failure! # => #<Mollie::SMS::Response failed (20) `No username given.'>
|
68
|
+
|
69
|
+
response = sms.deliver # => #<Mollie::SMS::Response failed (20) `No username given.'>
|
70
|
+
response.success? # => false
|
71
|
+
response.result_code # => 20
|
72
|
+
response.message # => "No username given."
|
73
|
+
|
74
|
+
Mollie::SMS.deliveries
|
75
|
+
=> [#<Mollie::SMS from: <fngtps.nl> to: <+31681664814> body: "You have won a bowl of chicken noodle soup!">,
|
76
|
+
#<Mollie::SMS from: <fngtps.nl> to: <+31681664814> body: "You have won a bowl of chicken noodle soup!">]
|
77
|
+
|
78
|
+
= Rails
|
79
|
+
|
80
|
+
If you are using Rails and load the Mollie::SMS gem, it will automatically
|
81
|
+
require the test helper in test mode.
|
82
|
+
|
83
|
+
It also requires the test helper in development mode, so no actual SMS
|
84
|
+
messages can be send. Instead, the messages are logged to the
|
85
|
+
development.log.
|
86
|
+
|
87
|
+
= Contributing
|
88
|
+
|
89
|
+
Once you've made your great commits:
|
90
|
+
|
91
|
+
1. {http://help.github.com/forking Fork} Mollie-SMS
|
92
|
+
2. Create a topic branch
|
93
|
+
git checkout -b my_branch
|
94
|
+
3. Push to your branch
|
95
|
+
git push origin my_branch
|
96
|
+
4. Create an {http://github.com/Fingertips/Mollie-SMS/issues issue} with a link
|
97
|
+
to your branch
|
98
|
+
5. That's it!
|
99
|
+
|
100
|
+
= Copyright
|
101
|
+
|
102
|
+
Copyright (c) 2010 Eloy Duran, Fingertips <eloy@fngtps.com>
|
103
|
+
|
104
|
+
This software is MIT licensed. See {file:LICENSE} for more info.
|
data/Rakefile
CHANGED
@@ -5,8 +5,18 @@ task :spec do
|
|
5
5
|
sh "ruby ./spec/functional_sms_deliver_spec.rb"
|
6
6
|
end
|
7
7
|
|
8
|
+
desc "Run the specs with Kicker"
|
9
|
+
task :kick do
|
10
|
+
sh "kicker -c -e rake"
|
11
|
+
end
|
12
|
+
|
8
13
|
task :default => :spec
|
9
14
|
|
15
|
+
desc "Generate the docs with YARD"
|
16
|
+
task :doc do ||
|
17
|
+
sh "yardoc - README.rdoc LICENSE"
|
18
|
+
end
|
19
|
+
|
10
20
|
begin
|
11
21
|
require 'rubygems'
|
12
22
|
require 'jeweler'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
data/lib/mollie/sms.rb
CHANGED
@@ -8,10 +8,56 @@ rescue LoadError
|
|
8
8
|
end
|
9
9
|
require "active_support"
|
10
10
|
|
11
|
+
# The namespace for the Mollie.nl webservices.
|
12
|
+
#
|
13
|
+
# @see Mollie::SMS
|
11
14
|
module Mollie
|
15
|
+
# A class that allows you to send SMS messages through the Mollie.nl SMS
|
16
|
+
# webservice.
|
17
|
+
#
|
18
|
+
# See the {file:README.rdoc README} for examples on how to use this.
|
19
|
+
#
|
12
20
|
class SMS
|
21
|
+
# A collection of exception classes raised by Mollie::SMS.
|
22
|
+
module Exceptions
|
23
|
+
# The base class for Mollie::SMS exceptions.
|
24
|
+
class StandardError < ::StandardError; end
|
25
|
+
|
26
|
+
# The exception class which is used to indicate a validation error of one
|
27
|
+
# of the {SMS#params parameters} that would be send to the gateway.
|
28
|
+
class ValidationError < StandardError; end
|
29
|
+
|
30
|
+
# The exception class which is used to indicate a delivery failure, when
|
31
|
+
# the {SMS#deliver!} method is used and delivery fails.
|
32
|
+
class DeliveryFailure < StandardError
|
33
|
+
# @return [SMS] The Mollie::SMS instance.
|
34
|
+
attr_reader :sms
|
35
|
+
|
36
|
+
# @return [Response] The Mollie::SMS::Response instance.
|
37
|
+
attr_reader :response
|
38
|
+
|
39
|
+
# @param [SMS] sms The Mollie::SMS instance.
|
40
|
+
# @param [Response] response The Mollie::SMS::Response instance.
|
41
|
+
def initialize(sms, response)
|
42
|
+
@sms, @response = sms, response
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [String] A string representation of the exception.
|
46
|
+
def message
|
47
|
+
"(#{@response.message}) #{@sms.to_s}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# The SSL URI to which the parameters of a SMS are posted.
|
53
|
+
#
|
54
|
+
# Note that the certificate is *not* verified.
|
13
55
|
GATEWAY_URI = URI.parse("https://secure.mollie.nl/xml/sms")
|
14
56
|
|
57
|
+
# The possible values that indicate which {SMS.gateway= SMS gateway} should
|
58
|
+
# be used.
|
59
|
+
#
|
60
|
+
# @see http://www.mollie.nl/sms-diensten/sms-gateway/gateways
|
15
61
|
GATEWAYS = {
|
16
62
|
'basic' => '2',
|
17
63
|
'business' => '4',
|
@@ -19,31 +65,69 @@ module Mollie
|
|
19
65
|
'landline' => '8'
|
20
66
|
}
|
21
67
|
|
22
|
-
|
23
|
-
|
24
|
-
class MissingRequiredParam < StandardError; end
|
25
|
-
|
26
|
-
class DeliveryFailure < StandardError
|
27
|
-
attr_reader :sms, :response
|
28
|
-
|
29
|
-
def initialize(sms, response)
|
30
|
-
@sms, @response = sms, response
|
31
|
-
end
|
32
|
-
|
33
|
-
def message
|
34
|
-
"(#{@response.message}) #{@sms.to_s}"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
68
|
+
# A list of paramaters that *must* to be included in the
|
69
|
+
# {SMS#params parameters} send to the gateway.
|
38
70
|
REQUIRED_PARAMS = %w{ username md5_password originator gateway charset type recipients message }
|
39
71
|
|
40
72
|
class << self
|
41
|
-
|
73
|
+
# @return [String] Your username for the Mollie.nl SMS webservice.
|
74
|
+
attr_accessor :username
|
42
75
|
|
76
|
+
# @return [String] A MD5 hashed version of your password for the
|
77
|
+
# Mollie.nl SMS webservice.
|
78
|
+
attr_reader :password
|
43
79
|
def password=(password)
|
44
80
|
@password = Digest::MD5.hexdigest(password)
|
45
81
|
end
|
46
82
|
|
83
|
+
# The number, or display name, that will be used to indicate the
|
84
|
+
# originator of a message.
|
85
|
+
#
|
86
|
+
# It should be upto either fourteen numerical characters, or eleven
|
87
|
+
# alphanumerical characters.
|
88
|
+
#
|
89
|
+
# @see SMS#validate_params!
|
90
|
+
#
|
91
|
+
# @return [String] The originator
|
92
|
+
attr_accessor :originator
|
93
|
+
|
94
|
+
# @return [String] A character set name, describing the message’s body
|
95
|
+
# encoding. Defaults to ‘UTF-8’.
|
96
|
+
attr_accessor :charset
|
97
|
+
|
98
|
+
# The type of messages that will be send. Possible values are:
|
99
|
+
# * normal
|
100
|
+
# * wappush
|
101
|
+
# * vcard
|
102
|
+
# * flash
|
103
|
+
# * binary
|
104
|
+
# * long
|
105
|
+
#
|
106
|
+
# Defaults to ‘normal’
|
107
|
+
#
|
108
|
+
# @return [String] The message type.
|
109
|
+
attr_accessor :type
|
110
|
+
|
111
|
+
# The gateway that should be used to send messages. Possible values are:
|
112
|
+
# * {GATEWAYS GATEWAYS['basic']}
|
113
|
+
# * {GATEWAYS GATEWAYS['business']}
|
114
|
+
# * {GATEWAYS GATEWAYS['business+']}
|
115
|
+
# * {GATEWAYS GATEWAYS['landline']}
|
116
|
+
#
|
117
|
+
# Defaults to ‘basic’.
|
118
|
+
#
|
119
|
+
# @see http://www.mollie.nl/sms-diensten/sms-gateway/gateways
|
120
|
+
#
|
121
|
+
# @return [String] The gateway ID.
|
122
|
+
attr_accessor :gateway
|
123
|
+
|
124
|
+
# Returns the default parameters that will be we merged with each
|
125
|
+
# instance’s params.
|
126
|
+
#
|
127
|
+
# This includes +username+, +md5_password+, +originator+, +gateway+,
|
128
|
+
# +charset+, and +type+.
|
129
|
+
#
|
130
|
+
# @return [Hash]
|
47
131
|
def default_params
|
48
132
|
{
|
49
133
|
'username' => @username,
|
@@ -60,42 +144,78 @@ module Mollie
|
|
60
144
|
self.type = 'normal'
|
61
145
|
self.gateway = GATEWAYS['basic']
|
62
146
|
|
147
|
+
# @return [Hash] The parameters that will be send to the gateway.
|
63
148
|
attr_reader :params
|
64
149
|
|
150
|
+
# Initializes a new Mollie::SMS instance.
|
151
|
+
#
|
152
|
+
# You can either specify the recipient’s telephone number and message
|
153
|
+
# body here, or later on through the accessors for these attributes.
|
154
|
+
#
|
155
|
+
# @param [String] telephone_number The recipient’s telephone number.
|
156
|
+
#
|
157
|
+
# @param [String] body The message body.
|
158
|
+
#
|
159
|
+
# @param [Hash] extra_params Optional parameters that are to be merged with
|
160
|
+
# the {SMS.default_params default parameters}.
|
65
161
|
def initialize(telephone_number = nil, body = nil, extra_params = {})
|
66
162
|
@params = self.class.default_params.merge(extra_params)
|
67
163
|
self.telephone_number = telephone_number if telephone_number
|
68
164
|
self.body = body if body
|
69
165
|
end
|
70
166
|
|
167
|
+
# @return [String] The recipient’s telephone number.
|
71
168
|
def telephone_number
|
72
169
|
@params['recipients']
|
73
170
|
end
|
74
171
|
|
172
|
+
# Assigns the recipient’s telephone number.
|
173
|
+
#
|
174
|
+
# @param [String] telephone_number The recipient’s telephone number.
|
175
|
+
# @return [String] The recipient’s telephone number.
|
75
176
|
def telephone_number=(telephone_number)
|
76
177
|
@params['recipients'] = telephone_number
|
77
178
|
end
|
78
179
|
|
180
|
+
# @return [String] The message body.
|
79
181
|
def body
|
80
182
|
@params['message']
|
81
183
|
end
|
82
184
|
|
185
|
+
# Assigns the message’s body.
|
186
|
+
#
|
187
|
+
# @param [String] body The message’s body.
|
188
|
+
# @return [String] The message’s body.
|
83
189
|
def body=(body)
|
84
190
|
@params['message'] = body
|
85
191
|
end
|
86
192
|
|
193
|
+
# Compares whether or not this and the +other+ Mollie::SMS instance are
|
194
|
+
# equal in recipient, body, and other parameters.
|
195
|
+
#
|
196
|
+
# @param [SMS] other The Mollie::SMS instance to compare against.
|
197
|
+
# @return [Boolean]
|
87
198
|
def ==(other)
|
88
199
|
other.is_a?(SMS) && other.params == params
|
89
200
|
end
|
90
201
|
|
202
|
+
# @return [String] A string representation of this instance.
|
91
203
|
def to_s
|
92
204
|
%{from: <#{params['originator']}> to: <#{telephone_number}> body: "#{body}"}
|
93
205
|
end
|
94
206
|
|
207
|
+
# @return [String] A `inspect' string representation of this instance.
|
95
208
|
def inspect
|
96
209
|
%{#<#{self.class.name} #{to_s}>}
|
97
210
|
end
|
98
211
|
|
212
|
+
# Posts the {#params parameters} to the gateway, through SSL.
|
213
|
+
#
|
214
|
+
# The params are validated before attempting to post them.
|
215
|
+
# @see #validate_params!
|
216
|
+
#
|
217
|
+
# @return [Response] A response object which encapsulates the result of the
|
218
|
+
# request.
|
99
219
|
def deliver
|
100
220
|
validate_params!
|
101
221
|
|
@@ -103,60 +223,120 @@ module Mollie
|
|
103
223
|
post.form_data = params
|
104
224
|
request = Net::HTTP.new(GATEWAY_URI.host, GATEWAY_URI.port)
|
105
225
|
request.use_ssl = true
|
226
|
+
request.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
106
227
|
request.start do |http|
|
107
228
|
response = http.request(post)
|
108
229
|
Response.new(response)
|
109
230
|
end
|
110
231
|
end
|
111
232
|
|
233
|
+
# Posts the {#params parameters} through {#deliver}, but raises a
|
234
|
+
# DeliveryFailure in case the request fails.
|
235
|
+
#
|
236
|
+
# This happens if an HTTP error occurs, or the gateway didn’t accept the
|
237
|
+
# {#params parameters}.
|
238
|
+
#
|
239
|
+
# @return [Response] Upon success, a response object which encapsulates the
|
240
|
+
# result of the request.
|
241
|
+
#
|
242
|
+
# @raise [DeliveryFailure] An exception which encapsulates this {SMS SMS}
|
243
|
+
# instance and the {Response} object.
|
112
244
|
def deliver!
|
113
245
|
response = deliver
|
114
|
-
raise DeliveryFailure.new(self, response) unless response.success?
|
246
|
+
raise Exceptions::DeliveryFailure.new(self, response) unless response.success?
|
115
247
|
response
|
116
248
|
end
|
117
249
|
|
250
|
+
# Checks if all {REQUIRED_PARAMS required parameters} are present and if
|
251
|
+
# the {SMS.originator} is of the right size.
|
252
|
+
#
|
253
|
+
# @see SMS.originator
|
254
|
+
#
|
255
|
+
# @raise [ValidationError] If any of the validations fail.
|
256
|
+
#
|
257
|
+
# @return [nil]
|
118
258
|
def validate_params!
|
119
259
|
params.slice(*REQUIRED_PARAMS).each do |key, value|
|
120
|
-
raise
|
260
|
+
raise Exceptions::ValidationError, "The required parameter `#{key}' is missing." if value.blank?
|
121
261
|
end
|
122
262
|
|
123
263
|
originator = params['originator']
|
124
264
|
if originator =~ /^\d+$/
|
125
265
|
if originator.size > 14
|
126
|
-
raise ValidationError, "Originator may have a maximimun of 14 numerical characters."
|
266
|
+
raise Exceptions::ValidationError, "Originator may have a maximimun of 14 numerical characters."
|
127
267
|
end
|
128
268
|
elsif originator.size > 11
|
129
|
-
raise ValidationError, "Originator may have a maximimun of 11 alphanumerical characters."
|
269
|
+
raise Exceptions::ValidationError, "Originator may have a maximimun of 11 alphanumerical characters."
|
130
270
|
end
|
131
271
|
end
|
132
272
|
|
273
|
+
# This class encapsulates the HTTP response and the response from the
|
274
|
+
# gateway. Put shortly, instances of this class return whether or not a SMS
|
275
|
+
# message has been delivered.
|
133
276
|
class Response
|
277
|
+
# @return [Net::HTTPResponse] The raw HTTP response object.
|
134
278
|
attr_reader :http_response
|
135
279
|
|
280
|
+
# Initializes a new Mollie::SMS::Response instance.
|
281
|
+
#
|
282
|
+
# @param [Net::HTTPResponse] http_response The HTTP response object.
|
136
283
|
def initialize(http_response)
|
137
284
|
@http_response = http_response
|
138
285
|
end
|
139
286
|
|
287
|
+
# @return [Hash] The response parameters from the gateway. Or an empty
|
288
|
+
# Hash if a HTTP error occurred.
|
140
289
|
def params
|
141
290
|
@params ||= http_failure? ? {} : Hash.from_xml(@http_response.read_body)['response']['item']
|
142
291
|
end
|
143
292
|
|
293
|
+
# Upon success, returns the result code from the gateway. Otherwise the
|
294
|
+
# HTTP response code.
|
295
|
+
#
|
296
|
+
# The possible gateway result codes are:
|
297
|
+
# * 10 - message sent
|
298
|
+
# * 20 - no ‘username’
|
299
|
+
# * 21 - no ‘password’
|
300
|
+
# * 22 - no, or incorrect, ‘originator’
|
301
|
+
# * 23 - no ‘recipients’
|
302
|
+
# * 24 - no ‘message’
|
303
|
+
# * 25 - incorrect ‘recipients’
|
304
|
+
# * 26 - incorrect ‘originator’
|
305
|
+
# * 27 - incorrect ‘message’
|
306
|
+
# * 28 - charset failure
|
307
|
+
# * 29 - parameter failure
|
308
|
+
# * 30 - incorrect ‘username’ or ‘password’
|
309
|
+
# * 31 - not enough credits to send message
|
310
|
+
# * 38 - binary UDH parameter misformed
|
311
|
+
# * 39 - ‘deliverydate’ format is not correct
|
312
|
+
# * 98 - gateway unreachable
|
313
|
+
# * 99 - unknown error
|
314
|
+
#
|
315
|
+
# @return [Integer] The result code from the gateway or HTTP response
|
316
|
+
# code.
|
144
317
|
def result_code
|
145
318
|
(http_failure? ? @http_response.code : params['resultcode']).to_i
|
146
319
|
end
|
147
320
|
|
321
|
+
# @return [String] The message from the gateway, or the HTTP message in
|
322
|
+
# case of a HTTP error.
|
323
|
+
#
|
324
|
+
# @see #result_code #result_code for a list of possible messages.
|
148
325
|
def message
|
149
326
|
http_failure? ? "[HTTP: #{@http_response.code}] #{@http_response.message}" : params['resultmessage']
|
150
327
|
end
|
151
328
|
|
329
|
+
# @return [Boolean] Whether or not the SMS message has been delivered.
|
152
330
|
def success?
|
153
331
|
!http_failure? && params['success'] == 'true'
|
154
332
|
end
|
155
333
|
|
334
|
+
# @return [Boolean] Whether or not the HTTP request was a success.
|
156
335
|
def http_failure?
|
157
336
|
!@http_response.is_a?(Net::HTTPSuccess)
|
158
337
|
end
|
159
338
|
|
339
|
+
# @return [String] A `inspect' string representation of this instance.
|
160
340
|
def inspect
|
161
341
|
"#<#{self.class.name} #{ success? ? 'succeeded' : 'failed' } (#{result_code}) `#{message}'>"
|
162
342
|
end
|
@@ -1,44 +1,13 @@
|
|
1
1
|
module Mollie
|
2
2
|
class SMS
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
success!
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.success!
|
13
|
-
http_response = Net::HTTPOK.new('1.1', '200', 'OK')
|
14
|
-
http_response.add_field('Content-type', 'application/xml')
|
15
|
-
def http_response.read_body; TestHelper::SUCCESS_BODY; end
|
16
|
-
@stubbed_response = Mollie::SMS::Response.new(http_response)
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.gateway_failure!
|
20
|
-
http_response = Net::HTTPOK.new('1.1', '200', 'OK')
|
21
|
-
http_response.add_field('Content-type', 'application/xml')
|
22
|
-
def http_response.read_body; TestHelper::FAILURE_BODY; end
|
23
|
-
@stubbed_response = Mollie::SMS::Response.new(http_response)
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.http_failure!
|
27
|
-
@stubbed_response = Mollie::SMS::Response.new(Net::HTTPBadRequest.new('1.1', '400', 'Bad request'))
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.stubbed_response
|
31
|
-
@stubbed_response || success!
|
32
|
-
end
|
33
|
-
|
34
|
-
def deliver
|
35
|
-
validate_params!
|
36
|
-
self.class.deliveries << self
|
37
|
-
self.class.stubbed_response
|
38
|
-
end
|
39
|
-
|
3
|
+
# A collection of helpers for testing the delivery of SMS messages.
|
4
|
+
#
|
5
|
+
# This includes:
|
6
|
+
# * a couple of Test::Unit {Mollie::SMS::TestHelper::Assertions assertions}
|
7
|
+
# * {Mollie::SMS::TestHelper::SMSExt Mollie::SMS} class extensions and
|
8
|
+
# overrides
|
40
9
|
module TestHelper
|
41
|
-
|
10
|
+
SUCCESS_BODY = %{
|
42
11
|
<?xml version="1.0" ?>
|
43
12
|
<response>
|
44
13
|
<item type="sms">
|
@@ -49,7 +18,7 @@ module Mollie
|
|
49
18
|
</item>
|
50
19
|
</response>}
|
51
20
|
|
52
|
-
|
21
|
+
FAILURE_BODY = %{
|
53
22
|
<?xml version="1.0"?>
|
54
23
|
<response>
|
55
24
|
<item type="sms">
|
@@ -60,17 +29,175 @@ module Mollie
|
|
60
29
|
</item>
|
61
30
|
</response>}
|
62
31
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
32
|
+
# A couple of Test::Unit assertions, to test the amount of sent messages.
|
33
|
+
module Assertions
|
34
|
+
# Asserts that a specific number of SMS messages have been sent, for the
|
35
|
+
# duration of the given block.
|
36
|
+
#
|
37
|
+
# def test_invitation_message_is_sent
|
38
|
+
# assert_sms_messages(1) do
|
39
|
+
# Account.create(:telephone_number => "+31621212121")
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# @yield The context that will be used to check the number of sent
|
44
|
+
# messages.
|
45
|
+
#
|
46
|
+
# @return [nil]
|
47
|
+
#
|
48
|
+
# @see Mollie::SMS::TestHelper::SMSExt::ClassMethods#deliveries
|
49
|
+
# Mollie::SMS.deliveries
|
50
|
+
def assert_sms_messages(number_of_messages)
|
51
|
+
before = Mollie::SMS.deliveries.length
|
52
|
+
yield
|
53
|
+
diff = Mollie::SMS.deliveries.length - before
|
54
|
+
assert(diff == number_of_messages, "expected `#{number_of_messages}' SMS messages to be sent, actually sent `#{diff}'")
|
55
|
+
end
|
56
|
+
|
57
|
+
# Asserts that *no* SMS messages have been sent, for the duration of the
|
58
|
+
# given block.
|
59
|
+
#
|
60
|
+
# def test_no_invitation_message_is_sent_when_account_is_invalid
|
61
|
+
# assert_no_sms_messages do
|
62
|
+
# Account.create(:telephone_number => "invalid")
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# @yield The context that will be used to check the number of sent
|
67
|
+
# messages.
|
68
|
+
#
|
69
|
+
# @return [nil]
|
70
|
+
#
|
71
|
+
# @see Mollie::SMS::TestHelper::SMSExt::ClassMethods#deliveries
|
72
|
+
# Mollie::SMS.deliveries
|
73
|
+
def assert_no_sms_messages
|
74
|
+
assert_sms_messages(0) { yield }
|
75
|
+
end
|
68
76
|
end
|
69
77
|
|
70
|
-
|
71
|
-
|
78
|
+
# Extensions and overrides of the Mollie::SMS class for testing purposes.
|
79
|
+
#
|
80
|
+
# The class method extensions are defined on the
|
81
|
+
# {Mollie::SMS::TestHelper::SMSExt::ClassMethods ClassMethods} module.
|
82
|
+
module SMSExt
|
83
|
+
# @private
|
84
|
+
def self.included(klass)
|
85
|
+
klass.class_eval do
|
86
|
+
undef_method :deliver
|
87
|
+
alias_method :deliver, :test_deliver
|
88
|
+
extend ClassMethods
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Overrides the normal {Mollie::SMS#deliver deliver} method to *never*
|
93
|
+
# make an actual request.
|
94
|
+
#
|
95
|
+
# Instead, the SMS message, that’s to be delivered, is added to the
|
96
|
+
# {Mollie::SMS::TestHelper::SMSExt::ClassMethods#deliveries
|
97
|
+
# Mollie::SMS.deliveries} list for later inspection.
|
98
|
+
#
|
99
|
+
# The parameters are still validated.
|
100
|
+
#
|
101
|
+
# @return [Response] The stubbed Response instance.
|
102
|
+
#
|
103
|
+
# @see Mollie::SMS::TestHelper::SMSExt::ClassMethods#stubbed_response
|
104
|
+
# Mollie::SMS.stubbed_response
|
105
|
+
def deliver
|
106
|
+
validate_params!
|
107
|
+
self.class.deliveries << self
|
108
|
+
self.class.stubbed_response
|
109
|
+
end
|
110
|
+
|
111
|
+
alias_method :test_deliver, :deliver
|
112
|
+
|
113
|
+
module ClassMethods
|
114
|
+
# @return [Array<Mollie::SMS>] A list of sent SMS messages.
|
115
|
+
#
|
116
|
+
# @see Mollie::SMS::TestHelper::SMSExt#deliver
|
117
|
+
# Mollie::SMS#deliver
|
118
|
+
def deliveries
|
119
|
+
@deliveries ||= []
|
120
|
+
end
|
121
|
+
|
122
|
+
# Clears the {#deliveries deliveries} list and stubs a {#success!
|
123
|
+
# ‘success’} Response instance.
|
124
|
+
#
|
125
|
+
# @return [Response] The stubbed ‘success’ Response instance.
|
126
|
+
def reset!
|
127
|
+
@deliveries = []
|
128
|
+
success!
|
129
|
+
end
|
130
|
+
|
131
|
+
# Stubs a ‘success’ Response instance.
|
132
|
+
#
|
133
|
+
# This means that any following calls to {Mollie::SMS#deliver} will
|
134
|
+
# succeed and return the stubbed ‘success’ Response instance.
|
135
|
+
#
|
136
|
+
# Mollie::SMS.success!
|
137
|
+
# response = Mollie::SMS.new(number, body).deliver
|
138
|
+
# response.success? # => true
|
139
|
+
# response.result_code # => 10
|
140
|
+
# response.message # => "Message successfully sent."
|
141
|
+
#
|
142
|
+
# @return [Response] The stubbed ‘success’ Response instance.
|
143
|
+
def success!
|
144
|
+
http_response = Net::HTTPOK.new('1.1', '200', 'OK')
|
145
|
+
http_response.add_field('Content-type', 'application/xml')
|
146
|
+
# @private
|
147
|
+
def http_response.read_body; TestHelper::SUCCESS_BODY; end
|
148
|
+
@stubbed_response = Mollie::SMS::Response.new(http_response)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Stubs a ‘gateway failure’ Response instance.
|
152
|
+
#
|
153
|
+
# This means that any following calls to {Mollie::SMS#deliver} will
|
154
|
+
# fail at the gateway and return the stubbed ‘gateway failure’
|
155
|
+
# Response instance.
|
156
|
+
#
|
157
|
+
# Mollie::SMS.gateway_failure!
|
158
|
+
# response = Mollie::SMS.new(number, body).deliver
|
159
|
+
# response.success? # => false
|
160
|
+
# response.result_code # => 20
|
161
|
+
# response.message # => "No username given."
|
162
|
+
#
|
163
|
+
# @return [Response] The stubbed ‘gateway failure’ Response
|
164
|
+
# instance.
|
165
|
+
def gateway_failure!
|
166
|
+
http_response = Net::HTTPOK.new('1.1', '200', 'OK')
|
167
|
+
http_response.add_field('Content-type', 'application/xml')
|
168
|
+
# @private
|
169
|
+
def http_response.read_body; TestHelper::FAILURE_BODY; end
|
170
|
+
@stubbed_response = Mollie::SMS::Response.new(http_response)
|
171
|
+
end
|
172
|
+
|
173
|
+
# Stubs a ‘HTTP failure’ Response instance.
|
174
|
+
#
|
175
|
+
# This means that any following calls to {Mollie::SMS#deliver} will
|
176
|
+
# fail at the HTTP level and return the stubbed ‘HTTP failure’
|
177
|
+
# Response instance.
|
178
|
+
#
|
179
|
+
# Mollie::SMS.http_failure!
|
180
|
+
# response = Mollie::SMS.new(number, body).deliver
|
181
|
+
# response.success? # => false
|
182
|
+
# response.result_code # => 400
|
183
|
+
# response.message # => "[HTTP: 400] Bad request"
|
184
|
+
#
|
185
|
+
# @return [Response] The stubbed ‘HTTP failure’ Response
|
186
|
+
# instance.
|
187
|
+
def http_failure!
|
188
|
+
@stubbed_response = Mollie::SMS::Response.new(Net::HTTPBadRequest.new('1.1', '400', 'Bad request'))
|
189
|
+
end
|
190
|
+
|
191
|
+
# @return [Response] The stubbed Response instance that will be
|
192
|
+
# returned for all requests from
|
193
|
+
# {Mollie::SMS#deliver}.
|
194
|
+
def stubbed_response
|
195
|
+
@stubbed_response || success!
|
196
|
+
end
|
197
|
+
end
|
72
198
|
end
|
73
199
|
end
|
74
200
|
end
|
75
201
|
end
|
76
202
|
|
203
|
+
Mollie::SMS.send(:include, Mollie::SMS::TestHelper::SMSExt)
|
data/mollie-sms.gemspec
CHANGED
@@ -5,20 +5,20 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mollie-sms}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "1.0.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Eloy Duran"]
|
12
|
-
s.date = %q{2010-08-
|
12
|
+
s.date = %q{2010-08-06}
|
13
13
|
s.description = %q{Send SMS text messages via the Mollie.nl SMS gateway.}
|
14
14
|
s.email = ["eloy@fngtps.com"]
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
|
-
"README"
|
17
|
+
"README.rdoc"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
"LICENSE",
|
21
|
-
"README",
|
21
|
+
"README.rdoc",
|
22
22
|
"Rakefile",
|
23
23
|
"VERSION",
|
24
24
|
"lib/mollie/sms.rb",
|
data/rails/init.rb
CHANGED
@@ -2,7 +2,7 @@ case Rails.env
|
|
2
2
|
when "test"
|
3
3
|
require 'mollie/sms/test_helper'
|
4
4
|
require 'active_support/test_case'
|
5
|
-
ActiveSupport::TestCase.send(:include, Mollie::SMS::TestHelper)
|
5
|
+
ActiveSupport::TestCase.send(:include, Mollie::SMS::TestHelper::Assertions)
|
6
6
|
when "development"
|
7
7
|
require 'mollie/sms/test_helper'
|
8
8
|
class Mollie::SMS
|
data/spec/sms_spec.rb
CHANGED
@@ -110,7 +110,7 @@ describe "When sending a Mollie::SMS message" do
|
|
110
110
|
exception = nil
|
111
111
|
begin
|
112
112
|
@sms.deliver!
|
113
|
-
rescue Mollie::SMS::DeliveryFailure => exception
|
113
|
+
rescue Mollie::SMS::Exceptions::DeliveryFailure => exception
|
114
114
|
end
|
115
115
|
|
116
116
|
exception.message.should == "(No username given.) #{@sms.to_s}"
|
@@ -210,7 +210,7 @@ describe "Mollie::SMS, concerning validation" do
|
|
210
210
|
@sms.params['originator'] = "000000000011112"
|
211
211
|
lambda do
|
212
212
|
@sms.deliver
|
213
|
-
end.should.raise(Mollie::SMS::ValidationError, "Originator may have a maximimun of 14 numerical characters.")
|
213
|
+
end.should.raise(Mollie::SMS::Exceptions::ValidationError, "Originator may have a maximimun of 14 numerical characters.")
|
214
214
|
end
|
215
215
|
|
216
216
|
it "accepts an originator of upto 11 alphanumerical characters" do
|
@@ -222,6 +222,6 @@ describe "Mollie::SMS, concerning validation" do
|
|
222
222
|
@sms.params['originator'] = "0123456789AB"
|
223
223
|
lambda do
|
224
224
|
@sms.deliver
|
225
|
-
end.should.raise(Mollie::SMS::ValidationError, "Originator may have a maximimun of 11 alphanumerical characters.")
|
225
|
+
end.should.raise(Mollie::SMS::Exceptions::ValidationError, "Originator may have a maximimun of 11 alphanumerical characters.")
|
226
226
|
end
|
227
227
|
end
|
data/spec/test_helper_spec.rb
CHANGED
@@ -44,8 +44,8 @@ describe "Mollie::SMS ext" do
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
describe "Mollie::SMS::TestHelper" do
|
48
|
-
extend Mollie::SMS::TestHelper
|
47
|
+
describe "Mollie::SMS::TestHelper::Assertions" do
|
48
|
+
extend Mollie::SMS::TestHelper::Assertions
|
49
49
|
|
50
50
|
before do
|
51
51
|
Mollie::SMS.reset!
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mollie-sms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
|
-
- 0
|
8
|
-
- 2
|
9
7
|
- 1
|
10
|
-
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Eloy Duran
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-08-
|
18
|
+
date: 2010-08-06 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -43,10 +43,10 @@ extensions: []
|
|
43
43
|
|
44
44
|
extra_rdoc_files:
|
45
45
|
- LICENSE
|
46
|
-
- README
|
46
|
+
- README.rdoc
|
47
47
|
files:
|
48
48
|
- LICENSE
|
49
|
-
- README
|
49
|
+
- README.rdoc
|
50
50
|
- Rakefile
|
51
51
|
- VERSION
|
52
52
|
- lib/mollie/sms.rb
|
data/README
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
A Ruby client that allows you to send SMS messages via http://mollie.nl.
|
2
|
-
|
3
|
-
It does only what we need, for our app, at this point in time. Which means that
|
4
|
-
connects to the webservice via SSL, and only sends a message to one recipient
|
5
|
-
at a time.
|
6
|
-
|
7
|
-
Patches are accepted.
|