em-kannel 0.2.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.
- data/.rspec +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +53 -0
- data/LICENSE +22 -0
- data/README.md +62 -0
- data/Rakefile +5 -0
- data/em-kannel.gemspec +26 -0
- data/lib/em-kannel.rb +39 -0
- data/lib/em-kannel/client.rb +39 -0
- data/lib/em-kannel/configuration.rb +39 -0
- data/lib/em-kannel/log_message.rb +30 -0
- data/lib/em-kannel/message.rb +25 -0
- data/lib/em-kannel/response.rb +38 -0
- data/lib/em-kannel/test_helper.rb +28 -0
- data/lib/em-kannel/validations.rb +30 -0
- data/lib/em-kannel/version.rb +5 -0
- data/spec/em-kannel/client_spec.rb +85 -0
- data/spec/em-kannel/configuration_spec.rb +58 -0
- data/spec/em-kannel/message_spec.rb +53 -0
- data/spec/em-kannel/response_spec.rb +54 -0
- data/spec/em-kannel/validations_spec.rb +30 -0
- data/spec/em-kannel_spec.rb +14 -0
- data/spec/spec_helper.rb +8 -0
- metadata +148 -0
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
em-kannel (0.2.0)
|
5
|
+
activemodel (~> 3.1)
|
6
|
+
em-http-request (>= 1.0.0.beta.4)
|
7
|
+
eventmachine (>= 1.0.0.beta.3)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: http://rubygems.org/
|
11
|
+
specs:
|
12
|
+
activemodel (3.1.3)
|
13
|
+
activesupport (= 3.1.3)
|
14
|
+
builder (~> 3.0.0)
|
15
|
+
i18n (~> 0.6)
|
16
|
+
activesupport (3.1.3)
|
17
|
+
multi_json (~> 1.0)
|
18
|
+
addressable (2.2.6)
|
19
|
+
builder (3.0.0)
|
20
|
+
cookiejar (0.3.0)
|
21
|
+
crack (0.3.1)
|
22
|
+
diff-lcs (1.1.3)
|
23
|
+
em-http-request (1.0.1)
|
24
|
+
addressable (>= 2.2.3)
|
25
|
+
cookiejar
|
26
|
+
em-socksify
|
27
|
+
eventmachine (>= 1.0.0.beta.4)
|
28
|
+
http_parser.rb (>= 0.5.3)
|
29
|
+
em-socksify (0.1.0)
|
30
|
+
eventmachine
|
31
|
+
eventmachine (1.0.0.beta.4)
|
32
|
+
http_parser.rb (0.5.3)
|
33
|
+
i18n (0.6.0)
|
34
|
+
multi_json (1.0.4)
|
35
|
+
rspec (2.7.0)
|
36
|
+
rspec-core (~> 2.7.0)
|
37
|
+
rspec-expectations (~> 2.7.0)
|
38
|
+
rspec-mocks (~> 2.7.0)
|
39
|
+
rspec-core (2.7.0)
|
40
|
+
rspec-expectations (2.7.0)
|
41
|
+
diff-lcs (~> 1.1.2)
|
42
|
+
rspec-mocks (2.7.0)
|
43
|
+
webmock (1.7.7)
|
44
|
+
addressable (~> 2.2, > 2.2.5)
|
45
|
+
crack (>= 0.1.7)
|
46
|
+
|
47
|
+
PLATFORMS
|
48
|
+
ruby
|
49
|
+
|
50
|
+
DEPENDENCIES
|
51
|
+
em-kannel!
|
52
|
+
rspec (~> 2.7.0)
|
53
|
+
webmock (~> 1.7.7)
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
(The MIT-License)
|
2
|
+
|
3
|
+
Copyright (c) 2011 GroupMe
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Kannel SMS delivery for EventMachine
|
2
|
+
|
3
|
+
# Install
|
4
|
+
|
5
|
+
gem "em-kannel", :git => "git://github.com/groupme/em-kannel.git"
|
6
|
+
|
7
|
+
# Usage
|
8
|
+
|
9
|
+
require "em-kannel"
|
10
|
+
|
11
|
+
kannel = EM::Kannel.new(
|
12
|
+
username: "user",
|
13
|
+
password: "password",
|
14
|
+
url: "http://www.example.com/sendsms"
|
15
|
+
)
|
16
|
+
|
17
|
+
|
18
|
+
EM.run do
|
19
|
+
kannel.sendsms(
|
20
|
+
from: "+12105551010",
|
21
|
+
to: "+12125551212 +17185551212",
|
22
|
+
body: "Hello World"
|
23
|
+
)
|
24
|
+
EM.stop
|
25
|
+
end
|
26
|
+
|
27
|
+
## Callbacks
|
28
|
+
|
29
|
+
You can pass a block to process the response body:
|
30
|
+
|
31
|
+
kannel.sendsms(message_options) do |response|
|
32
|
+
if response.success?
|
33
|
+
log("Hooray!")
|
34
|
+
else
|
35
|
+
log("Boo! #{response.body}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Testing
|
40
|
+
|
41
|
+
To test em-kannel's deliveries, start by simply requiring this file after EM::Kannel has already
|
42
|
+
been loaded:
|
43
|
+
|
44
|
+
require "em-kannel"
|
45
|
+
require "em-kannel/test_helper"
|
46
|
+
|
47
|
+
This will nullify actual deliveries and instead, push them onto an accessible
|
48
|
+
list:
|
49
|
+
|
50
|
+
kannel = EM::Kannel.new(configuration_options)
|
51
|
+
|
52
|
+
expect {
|
53
|
+
kannel.send_sms(message_options)
|
54
|
+
}.to change { EM::Kannel.deliveries.size }.by(1)
|
55
|
+
|
56
|
+
message = EM::Kannel.deliveries.first
|
57
|
+
message.should be_an_instance_of(EM::Kannel::Message)
|
58
|
+
message.body.should == ...
|
59
|
+
|
60
|
+
# Legal
|
61
|
+
|
62
|
+
See LICENSE for details
|
data/Rakefile
ADDED
data/em-kannel.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
|
3
|
+
require "em-kannel/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "em-kannel"
|
7
|
+
s.version = EventMachine::Kannel::VERSION
|
8
|
+
s.authors = ["John Pignata"]
|
9
|
+
s.email = ["john@groupme.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{EventMachine-driven SMS delivery via Kannel}
|
12
|
+
|
13
|
+
s.rubyforge_project = "em-kannel"
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_dependency "eventmachine", ">= 1.0.0.beta.3"
|
21
|
+
s.add_dependency "em-http-request", ">= 1.0.0.beta.4"
|
22
|
+
s.add_dependency "activemodel", "~> 3.1"
|
23
|
+
|
24
|
+
s.add_development_dependency "rspec", "~> 2.7.0"
|
25
|
+
s.add_development_dependency "webmock", "~> 1.7.7"
|
26
|
+
end
|
data/lib/em-kannel.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require "active_model"
|
2
|
+
require "active_support/core_ext/hash"
|
3
|
+
require "em-http-request"
|
4
|
+
require "logger"
|
5
|
+
|
6
|
+
require "em-kannel/validations"
|
7
|
+
require "em-kannel/configuration"
|
8
|
+
require "em-kannel/message"
|
9
|
+
require "em-kannel/log_message"
|
10
|
+
require "em-kannel/client"
|
11
|
+
require "em-kannel/response"
|
12
|
+
|
13
|
+
module EventMachine
|
14
|
+
class Kannel
|
15
|
+
attr_accessor :configuration
|
16
|
+
|
17
|
+
def initialize(configuration_options={})
|
18
|
+
self.configuration = Configuration.new(configuration_options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.logger
|
22
|
+
@logger ||= Logger.new(STDOUT)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.logger=(new_logger)
|
26
|
+
@logger = new_logger
|
27
|
+
end
|
28
|
+
|
29
|
+
def send_sms(message_options, &block)
|
30
|
+
configuration.validate!
|
31
|
+
|
32
|
+
message = Message.new(message_options)
|
33
|
+
message.validate!
|
34
|
+
|
35
|
+
client = Client.new(message, configuration)
|
36
|
+
client.deliver(&block)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module EventMachine
|
2
|
+
class Kannel
|
3
|
+
class Client
|
4
|
+
attr_accessor :message, :configuration
|
5
|
+
|
6
|
+
def initialize(message, configuration)
|
7
|
+
self.message = message
|
8
|
+
self.configuration = configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
def deliver(&block)
|
12
|
+
start = Time.now.to_f
|
13
|
+
http = EM::HttpRequest.new(configuration.url, options).get(query: query)
|
14
|
+
|
15
|
+
http.callback { callback(http, start, message, &block) }
|
16
|
+
http.errback { callback(http, start, message, &block) }
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def options
|
22
|
+
{ ssl: { verify_peer: configuration.verify_ssl_peer } }
|
23
|
+
end
|
24
|
+
|
25
|
+
def query
|
26
|
+
query = {}
|
27
|
+
query.merge!(configuration.as_query)
|
28
|
+
query.merge!(message.as_query)
|
29
|
+
end
|
30
|
+
|
31
|
+
def callback(http, start, message, &block)
|
32
|
+
response = Response.new(http, start)
|
33
|
+
|
34
|
+
LogMessage.new(message, response).log
|
35
|
+
block.call(response) if block_given?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module EventMachine
|
2
|
+
class Kannel
|
3
|
+
class Configuration
|
4
|
+
include Validations
|
5
|
+
|
6
|
+
attr_accessor :username,
|
7
|
+
:password,
|
8
|
+
:url,
|
9
|
+
:dlr_callback_url,
|
10
|
+
:dlr_mask,
|
11
|
+
:verify_ssl_peer,
|
12
|
+
:smsc
|
13
|
+
|
14
|
+
validates :username, presence: true
|
15
|
+
validates :password, presence: true
|
16
|
+
validates :url, presence: true
|
17
|
+
|
18
|
+
def initialize(attributes={})
|
19
|
+
attributes = attributes.with_indifferent_access
|
20
|
+
|
21
|
+
self.username = attributes[:username]
|
22
|
+
self.password = attributes[:password]
|
23
|
+
self.url = attributes[:url]
|
24
|
+
self.dlr_callback_url = attributes[:dlr_callback_url]
|
25
|
+
self.dlr_mask = attributes[:dlr_mask]
|
26
|
+
self.verify_ssl_peer = attributes[:verify_ssl_peer]
|
27
|
+
self.smsc = attributes[:smsc]
|
28
|
+
end
|
29
|
+
|
30
|
+
def as_query
|
31
|
+
query = { username: username, password: password }
|
32
|
+
query[:"dlr-mask"] = dlr_mask if dlr_mask
|
33
|
+
query[:"dlr-url"] = dlr_callback_url if dlr_callback_url
|
34
|
+
query[:smsc] = smsc if smsc
|
35
|
+
query
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module EventMachine
|
2
|
+
class Kannel
|
3
|
+
class LogMessage
|
4
|
+
def initialize(message, response)
|
5
|
+
@message, @response = message, response
|
6
|
+
end
|
7
|
+
|
8
|
+
def log
|
9
|
+
EM::Kannel.logger.info(message)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def message
|
15
|
+
parts = [
|
16
|
+
"CODE=#{@response.status}",
|
17
|
+
"FROM=#{@message.from}",
|
18
|
+
"TO=#{@message.to}",
|
19
|
+
"BODY=#{@message.body[0..100]}",
|
20
|
+
"RESPONSE=#{@response.body}",
|
21
|
+
"TIME=#{@response.duration}"
|
22
|
+
]
|
23
|
+
parts << "ERROR=#{@response.error}" unless @response.success?
|
24
|
+
|
25
|
+
parts.join(" ")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module EventMachine
|
2
|
+
class Kannel
|
3
|
+
class Message
|
4
|
+
include Validations
|
5
|
+
|
6
|
+
attr_accessor :body, :from, :to
|
7
|
+
|
8
|
+
validates :body, presence: true, length: { maximum: 160 }
|
9
|
+
validates :from, presence: true
|
10
|
+
validates :to, presence: true
|
11
|
+
|
12
|
+
def initialize(attributes={})
|
13
|
+
attributes = attributes.with_indifferent_access
|
14
|
+
|
15
|
+
self.from = attributes[:from]
|
16
|
+
self.to = attributes[:to]
|
17
|
+
self.body = attributes[:body]
|
18
|
+
end
|
19
|
+
|
20
|
+
def as_query
|
21
|
+
{ from: from, to: to, text: body }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module EventMachine
|
2
|
+
class Kannel
|
3
|
+
class Response
|
4
|
+
attr_reader :duration
|
5
|
+
|
6
|
+
def initialize(http, start=nil)
|
7
|
+
@http = http
|
8
|
+
@duration = compute_duration(start)
|
9
|
+
end
|
10
|
+
|
11
|
+
def status
|
12
|
+
@http.response_header.status.to_i
|
13
|
+
end
|
14
|
+
|
15
|
+
def success?
|
16
|
+
status == 202
|
17
|
+
end
|
18
|
+
|
19
|
+
def body
|
20
|
+
@http.response
|
21
|
+
end
|
22
|
+
|
23
|
+
def error
|
24
|
+
@http.error
|
25
|
+
end
|
26
|
+
|
27
|
+
def guid
|
28
|
+
body.split(": ").last
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def compute_duration(start)
|
34
|
+
start && ((Time.now.to_f - start.to_f) * 1000.0).round
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
|
3
|
+
module EventMachine
|
4
|
+
class Kannel
|
5
|
+
def self.deliveries
|
6
|
+
@deliveries ||= []
|
7
|
+
end
|
8
|
+
|
9
|
+
Client.class_eval do
|
10
|
+
def fake_response
|
11
|
+
guid = UUID.new.generate
|
12
|
+
|
13
|
+
status = OpenStruct.new(status: 202)
|
14
|
+
http = OpenStruct.new(
|
15
|
+
response_header: status,
|
16
|
+
response: "0: Accepted for delivery: #{guid}"
|
17
|
+
)
|
18
|
+
|
19
|
+
Response.new(http, Time.now)
|
20
|
+
end
|
21
|
+
|
22
|
+
def deliver(&block)
|
23
|
+
EM::Kannel.deliveries << @message
|
24
|
+
yield(fake_response) if block_given?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module EventMachine
|
2
|
+
class Kannel
|
3
|
+
module Validations
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
include ActiveModel::Validations
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate!
|
11
|
+
if invalid?
|
12
|
+
message = "Invalid #{friendly_name}: #{full_messages}"
|
13
|
+
raise ArgumentError.new(message)
|
14
|
+
end
|
15
|
+
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def friendly_name
|
20
|
+
self.class.model_name.human
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def full_messages
|
26
|
+
errors.full_messages.to_sentence
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe EventMachine::Kannel::Client do
|
4
|
+
describe "#deliver" do
|
5
|
+
let(:configuration) {
|
6
|
+
EM::Kannel::Configuration.new(
|
7
|
+
url: "http://www.example.com/api",
|
8
|
+
username: "user",
|
9
|
+
password: "pass"
|
10
|
+
)
|
11
|
+
}
|
12
|
+
|
13
|
+
let(:message) do
|
14
|
+
EM::Kannel::Message.new(
|
15
|
+
from: "+12125551212",
|
16
|
+
to: "+17185551212",
|
17
|
+
body: "testing"
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "delivers the message to the specified URL" do
|
22
|
+
stub = stub_request(:get, "http://www.example.com/api").with(
|
23
|
+
query: {
|
24
|
+
username: "user",
|
25
|
+
password: "pass",
|
26
|
+
from: "+12125551212",
|
27
|
+
to: "+17185551212",
|
28
|
+
text: "testing"
|
29
|
+
}
|
30
|
+
)
|
31
|
+
|
32
|
+
EM.run_block {
|
33
|
+
EM::Kannel::Client.new(message, configuration).deliver
|
34
|
+
}
|
35
|
+
|
36
|
+
stub.should have_been_requested
|
37
|
+
end
|
38
|
+
|
39
|
+
context "delivery succeeds" do
|
40
|
+
it "logs the delivery" do
|
41
|
+
uuid = "24b8d670-0ad6-012f-13e0-60c5470504ea"
|
42
|
+
|
43
|
+
stub = stub_request(:get, "http://www.example.com/api").with(
|
44
|
+
query: {
|
45
|
+
username: "user",
|
46
|
+
password: "pass",
|
47
|
+
from: "+12125551212",
|
48
|
+
to: "+17185551212",
|
49
|
+
text: "testing"
|
50
|
+
}).
|
51
|
+
to_return(:status => 202, :body => uuid)
|
52
|
+
|
53
|
+
EM::Kannel.logger.should_receive(:info).with(
|
54
|
+
/CODE=202 FROM=\+12125551212 TO=\+17185551212 BODY=testing RESPONSE=#{uuid} TIME=[0-9]/
|
55
|
+
)
|
56
|
+
|
57
|
+
EM.run_block {
|
58
|
+
EM::Kannel::Client.new(message, configuration).deliver
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "delivery fails" do
|
64
|
+
it "logs the failure" do
|
65
|
+
stub = stub_request(:get, "http://www.example.com/api").with(
|
66
|
+
query: {
|
67
|
+
username: "user",
|
68
|
+
password: "pass",
|
69
|
+
from: "+12125551212",
|
70
|
+
to: "+17185551212",
|
71
|
+
text: "testing"
|
72
|
+
}).
|
73
|
+
to_return(:status => 404, :body => "API not available")
|
74
|
+
|
75
|
+
EM::Kannel.logger.should_receive(:info).with(
|
76
|
+
/CODE=404 FROM=\+12125551212 TO=\+17185551212 BODY=testing RESPONSE=API not available TIME=[0-9]/
|
77
|
+
)
|
78
|
+
|
79
|
+
EM.run_block {
|
80
|
+
EM::Kannel::Client.new(message, configuration).deliver
|
81
|
+
}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe EventMachine::Kannel::Configuration do
|
4
|
+
let(:attributes) do
|
5
|
+
{
|
6
|
+
:username => "user",
|
7
|
+
:password => "pass",
|
8
|
+
:url => "http://www.example.com/url",
|
9
|
+
:dlr_callback_url => "http://www.example.com/dlr_callback_url",
|
10
|
+
:dlr_mask => 1,
|
11
|
+
:smsc => "Provider"
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
describe ".new" do
|
16
|
+
it "sets the attributes passed in the argument hash" do
|
17
|
+
configuration = EM::Kannel::Configuration.new(attributes)
|
18
|
+
|
19
|
+
attributes.each do |attribute_name, attribute_value|
|
20
|
+
configuration.send(attribute_name).should == attribute_value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "validations" do
|
26
|
+
let(:configuration) do
|
27
|
+
EM::Kannel::Configuration.new(
|
28
|
+
:username => "user",
|
29
|
+
:password => "pass"
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "validates presence of username" do
|
34
|
+
configuration.username = nil
|
35
|
+
configuration.should_not be_valid
|
36
|
+
configuration.errors[:username].should include("can't be blank")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "validates presence of password" do
|
40
|
+
configuration.password = nil
|
41
|
+
configuration.should_not be_valid
|
42
|
+
configuration.errors[:password].should include("can't be blank")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#as_query" do
|
47
|
+
it "returns a hash for use in the HTTP request" do
|
48
|
+
configuration = EM::Kannel::Configuration.new(attributes)
|
49
|
+
configuration.as_query.should == {
|
50
|
+
:username => "user",
|
51
|
+
:password => "pass",
|
52
|
+
:"dlr-mask" => 1,
|
53
|
+
:"dlr-url" => "http://www.example.com/dlr_callback_url",
|
54
|
+
:smsc => "Provider"
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe EventMachine::Kannel::Message do
|
4
|
+
let(:message) {
|
5
|
+
EM::Kannel::Message.new.tap do |message|
|
6
|
+
message.body = "hi there"
|
7
|
+
message.from = "+12125551212"
|
8
|
+
message.to = ["+17185551212"]
|
9
|
+
end
|
10
|
+
}
|
11
|
+
|
12
|
+
describe "validations" do
|
13
|
+
context "with valid attributes" do
|
14
|
+
it "is valid" do
|
15
|
+
message.should be_valid
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "validates presence of body" do
|
20
|
+
message.body = nil
|
21
|
+
message.should_not be_valid
|
22
|
+
message.errors[:body].should include("can't be blank")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "validates body length is at most 160 characters" do
|
26
|
+
message.body = "x" * 161
|
27
|
+
message.should_not be_valid
|
28
|
+
message.errors[:body].should include("is too long (maximum is 160 characters)")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "validates presence of from" do
|
32
|
+
message.from = nil
|
33
|
+
message.should_not be_valid
|
34
|
+
message.errors[:from].should include("can't be blank")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "validates presence of to" do
|
38
|
+
message.to = nil
|
39
|
+
message.should_not be_valid
|
40
|
+
message.errors[:to].should include("can't be blank")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#as_query" do
|
45
|
+
it "returns a hash for use in the HTTP request" do
|
46
|
+
message.as_query.should == {
|
47
|
+
from: "+12125551212",
|
48
|
+
to: ["+17185551212"],
|
49
|
+
text: "hi there"
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe EM::Kannel::Response do
|
4
|
+
let(:header) { mock(:header, status: "202") }
|
5
|
+
let(:body) { "0: Accepted for delivery: 26ecfeea-6015-4025-bcae-0d0b71467d83" }
|
6
|
+
let(:http) { mock(:http_client, response_header: header, response: body) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
now = Time.now
|
10
|
+
Time.stub(:now).and_return(now)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#status" do
|
14
|
+
it "returns the status code" do
|
15
|
+
started = Time.now - 10
|
16
|
+
http = mock(:http_client, response_header: header)
|
17
|
+
|
18
|
+
response = EM::Kannel::Response.new(http, started)
|
19
|
+
response.status.should == 202
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#success?" do
|
24
|
+
context "the status code is 202" do
|
25
|
+
it "returns true" do
|
26
|
+
response = EM::Kannel::Response.new(http)
|
27
|
+
response.should be_success
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "other status codes" do
|
32
|
+
let(:header) { mock(:header, status: "500") }
|
33
|
+
|
34
|
+
it "returns false" do
|
35
|
+
response = EM::Kannel::Response.new(http)
|
36
|
+
response.should_not be_success
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#body" do
|
42
|
+
it "returns the body of the response" do
|
43
|
+
response = EM::Kannel::Response.new(http)
|
44
|
+
response.body.should == body
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#guid" do
|
49
|
+
it "returns the guid of the response" do
|
50
|
+
response = EM::Kannel::Response.new(http)
|
51
|
+
response.guid.should == "26ecfeea-6015-4025-bcae-0d0b71467d83"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe EM::Kannel::Validations do
|
4
|
+
before do
|
5
|
+
class Model
|
6
|
+
include EM::Kannel::Validations
|
7
|
+
attr_accessor :value
|
8
|
+
validates :value, presence: true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#validate!" do
|
13
|
+
context "invalid" do
|
14
|
+
it "raises an ArgumentError" do
|
15
|
+
expect {
|
16
|
+
Model.new.validate!
|
17
|
+
}.to raise_exception(ArgumentError, /Invalid Model/)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "valid" do
|
22
|
+
it "returns true" do
|
23
|
+
instance = Model.new
|
24
|
+
instance.value = "value"
|
25
|
+
instance.validate!.should be_true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe EventMachine::Kannel do
|
4
|
+
describe ".send_sms" do
|
5
|
+
context "invalid configuration options" do
|
6
|
+
it "raises an ArgumentError with the validation errors" do
|
7
|
+
expect {
|
8
|
+
kannel = EM::Kannel.new({})
|
9
|
+
kannel.send_sms({})
|
10
|
+
}.to raise_exception(ArgumentError, /Invalid Configuration/)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: em-kannel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- John Pignata
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-10 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: eventmachine
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.0.0.beta.3
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.0.0.beta.3
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: em-http-request
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.0.0.beta.4
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.0.0.beta.4
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activemodel
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.1'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.1'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.7.0
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.7.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: webmock
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.7.7
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.7.7
|
94
|
+
description:
|
95
|
+
email:
|
96
|
+
- john@groupme.com
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- .rspec
|
102
|
+
- Gemfile
|
103
|
+
- Gemfile.lock
|
104
|
+
- LICENSE
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- em-kannel.gemspec
|
108
|
+
- lib/em-kannel.rb
|
109
|
+
- lib/em-kannel/client.rb
|
110
|
+
- lib/em-kannel/configuration.rb
|
111
|
+
- lib/em-kannel/log_message.rb
|
112
|
+
- lib/em-kannel/message.rb
|
113
|
+
- lib/em-kannel/response.rb
|
114
|
+
- lib/em-kannel/test_helper.rb
|
115
|
+
- lib/em-kannel/validations.rb
|
116
|
+
- lib/em-kannel/version.rb
|
117
|
+
- spec/em-kannel/client_spec.rb
|
118
|
+
- spec/em-kannel/configuration_spec.rb
|
119
|
+
- spec/em-kannel/message_spec.rb
|
120
|
+
- spec/em-kannel/response_spec.rb
|
121
|
+
- spec/em-kannel/validations_spec.rb
|
122
|
+
- spec/em-kannel_spec.rb
|
123
|
+
- spec/spec_helper.rb
|
124
|
+
homepage: ''
|
125
|
+
licenses: []
|
126
|
+
post_install_message:
|
127
|
+
rdoc_options: []
|
128
|
+
require_paths:
|
129
|
+
- lib
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ! '>='
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
requirements: []
|
143
|
+
rubyforge_project: em-kannel
|
144
|
+
rubygems_version: 1.8.19
|
145
|
+
signing_key:
|
146
|
+
specification_version: 3
|
147
|
+
summary: EventMachine-driven SMS delivery via Kannel
|
148
|
+
test_files: []
|