sms_broker 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,82 @@
1
+ module SmsBroker
2
+
3
+ class Setup
4
+
5
+ attr_reader :options,
6
+ :errors
7
+
8
+ def self.service_validation_schemas
9
+ {
10
+ nexmo: Compel.hash.keys({
11
+ key: Compel.string.required,
12
+ secret: Compel.string.required,
13
+ sender_id: Compel.string,
14
+ phone_number: Compel.string.required
15
+ }),
16
+ twilio: Compel.hash.keys({
17
+ sender_id: Compel.string,
18
+ auth_token: Compel.string.required,
19
+ account_sid: Compel.string.required,
20
+ phone_number: Compel.string.required
21
+ })
22
+ }
23
+ end
24
+
25
+ def initialize
26
+ @errors = {}
27
+ @options = {
28
+ services: ['nexmo'],
29
+ default_service: 'nexmo',
30
+ services_setups: {}
31
+ }
32
+ end
33
+
34
+ def services(services)
35
+ @options[:services] = services
36
+ end
37
+
38
+ def default_service(service)
39
+ @options[:default_service] = service
40
+ end
41
+
42
+ def valid?
43
+ result = compel_validation_schema(@options[:services]).validate(@options)
44
+
45
+ @errors = result.errors
46
+
47
+ result.valid?
48
+ end
49
+
50
+ def compel_validation_schema(services_list = [])
51
+ not_all_services_setup = Proc.new do |services_setups|
52
+ services_list.all?{ |service|
53
+ services_setups.keys.include?(service.to_sym)
54
+ }
55
+ end
56
+
57
+ services_setups_schema = \
58
+ Compel.hash.required
59
+ .keys(Setup.service_validation_schemas)
60
+ .if(not_all_services_setup, message: 'all services must be setup')
61
+
62
+ Compel.hash.keys \
63
+ services: Compel.array.required.min_length(1),
64
+ default_service: Compel.string.required.in(services_list),
65
+ services_setups: services_setups_schema
66
+ end
67
+
68
+ def method_missing(method, args, &block)
69
+ service = "#{method}".split('_setup')[0].dup
70
+
71
+ if @options[:services].include?(service)
72
+ @options[:services_setups][service.to_sym] = args
73
+ @options[:services_setups]
74
+ else
75
+
76
+ super
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -0,0 +1,5 @@
1
+ module SmsBroker
2
+
3
+ VERSION = '1.0.0'
4
+
5
+ end
data/lib/sms_broker.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'nexmo'
2
+ require 'compel'
3
+ require 'twilio-ruby'
4
+
5
+ require 'sms_broker/client/response/error'
6
+ require 'sms_broker/client/response/success'
7
+
8
+ require 'sms_broker/configuration'
9
+ require 'sms_broker/service'
10
+
11
+ module SmsBroker
12
+
13
+ extend Configuration
14
+
15
+ def service(name = default_service)
16
+ Service.get(name)
17
+ end
18
+
19
+ def message(body)
20
+ service.message(body)
21
+ end
22
+
23
+ extend self
24
+
25
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'sms_broker/version'
6
+
7
+ Gem::Specification.new do |gem|
8
+ gem.name = 'sms_broker'
9
+ gem.version = SmsBroker::VERSION
10
+ gem.authors = ['Streetbees Dev Team']
11
+ gem.email = ['dev@streetbees.com']
12
+ gem.description = %q{sms_broker}
13
+ gem.summary = %q{Sms Broker}
14
+ gem.homepage = 'https://github.com/streetbees/sms_broker'
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ['lib']
20
+
21
+ gem.add_runtime_dependency 'nexmo', '~> 4.2'
22
+ gem.add_runtime_dependency 'compel', '~> 0.5'
23
+ gem.add_runtime_dependency 'twilio-ruby', '~> 4.11'
24
+
25
+ gem.add_development_dependency 'webmock', '~> 2.0'
26
+ gem.add_development_dependency 'rspec', '~> 3.2'
27
+ gem.add_development_dependency 'rake', '~> 0'
28
+ gem.add_development_dependency 'pry', '~> 0'
29
+ end
@@ -0,0 +1,92 @@
1
+ describe SmsBroker do
2
+
3
+ context 'Nexmo' do
4
+
5
+ let(:text_message) { 'Hello World' }
6
+ let(:from_phone) { ENV['NEXMO_PHONE_NUMBER'] }
7
+ let(:api_secret) { ENV['NEXMO_API_SECRET'] }
8
+ let(:sender_id) { ENV['NEXMO_SENDER_ID'] }
9
+ let(:to_phone) { '44741234567' }
10
+ let(:api_key) { ENV['NEXMO_API_SECRET'] }
11
+
12
+ context '#send_message' do
13
+
14
+ before(:each) do
15
+ SmsBroker.clear_setup
16
+ end
17
+
18
+ context 'valid' do
19
+
20
+ it 'should send message with success' do
21
+ SmsBroker.setup do |config|
22
+ config.nexmo_setup \
23
+ phone_number: from_phone,
24
+ sender_id: sender_id,
25
+ secret: api_secret,
26
+ key: ENV['NEXMO_API_KEY']
27
+ end
28
+
29
+ stub_nexmo_create_message_success(sender_id, to_phone, text_message)
30
+
31
+ response = SmsBroker.message(text_message).to(to_phone).deliver
32
+
33
+ expect(response.service).to eq(:nexmo)
34
+ expect(response.success?).to eq(true)
35
+ expect(response.message_id).not_to eq(nil)
36
+ end
37
+
38
+ context 'with sender_id' do
39
+
40
+ it 'should return error for invalid sender_id' do
41
+ SmsBroker.setup do |config|
42
+ config.nexmo_setup \
43
+ phone_number: from_phone,
44
+ sender_id: sender_id,
45
+ secret: api_secret,
46
+ key: ENV['NEXMO_API_KEY']
47
+ end
48
+
49
+ stub_nexmo_create_message_success \
50
+ from_phone, to_phone, text_message
51
+
52
+ stub_nexmo_create_message_invalid_sender_id_request \
53
+ sender_id, to_phone, text_message
54
+
55
+ response = SmsBroker.message(text_message).to(to_phone).deliver
56
+
57
+ expect(response.success?).to eq(true)
58
+ # this means that it tried to send with sender_id and failed
59
+ # and then sent with from_phone
60
+ expect(response.from).to eq(from_phone)
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
67
+ context 'invalid' do
68
+
69
+ it 'should return error for invalid credentials' do
70
+ SmsBroker.setup do |config|
71
+ config.nexmo_setup \
72
+ phone_number: from_phone,
73
+ secret: 'invalid',
74
+ key: 'invalid'
75
+ end
76
+
77
+ stub_nexmo_create_message_invalid_credentials \
78
+ from_phone, to_phone, text_message
79
+
80
+ response = SmsBroker.message(text_message).to(to_phone).deliver
81
+
82
+ expect(response.success?).to eq(false)
83
+ expect(response.serialized.length).to be > 0
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+
92
+ end
@@ -0,0 +1,161 @@
1
+ describe SmsBroker do
2
+
3
+ context 'Setup' do
4
+
5
+ before(:each) do
6
+ SmsBroker.clear_setup
7
+ end
8
+
9
+ it 'should set configs' do
10
+ setup = \
11
+ SmsBroker.setup do |config|
12
+ config.services ['nexmo', 'twilio']
13
+
14
+ config.default_service 'nexmo'
15
+
16
+ config.nexmo_setup \
17
+ key: 'NEXMO_API_KEY',
18
+ phone_number: 'phone',
19
+ secret: 'NEXMO_API_KEY'
20
+
21
+ config.twilio_setup \
22
+ phone_number: 'phone',
23
+ account_sid: 'TWILIO_ACCOUNT_SID',
24
+ auth_token: 'TWILIO_AUTH_TOKEN'
25
+ end
26
+
27
+ expect(setup.valid?).to eq(true)
28
+
29
+ expect(setup.options[:services]).to \
30
+ eq(['nexmo', 'twilio'])
31
+
32
+ expect(setup.options[:default_service]).to \
33
+ eq('nexmo')
34
+
35
+ expect(setup.options[:services_setups][:nexmo]).to \
36
+ eq \
37
+ key: 'NEXMO_API_KEY',
38
+ secret: 'NEXMO_API_KEY',
39
+ phone_number: 'phone'
40
+
41
+ expect(setup.options[:services_setups][:twilio]).to \
42
+ eq \
43
+ phone_number: 'phone',
44
+ account_sid: 'TWILIO_ACCOUNT_SID',
45
+ auth_token: 'TWILIO_AUTH_TOKEN'
46
+ end
47
+
48
+ context 'valid configs' do
49
+
50
+ before(:each) do
51
+ SmsBroker.setup do |config|
52
+ config.services ['nexmo', 'twilio']
53
+
54
+ config.default_service 'nexmo'
55
+
56
+ config.nexmo_setup \
57
+ key: 'NEXMO_API_KEY',
58
+ phone_number: 'phone',
59
+ secret: 'NEXMO_API_KEY'
60
+
61
+ config.twilio_setup \
62
+ phone_number: 'phone',
63
+ account_sid: 'TWILIO_ACCOUNT_SID',
64
+ auth_token: 'TWILIO_AUTH_TOKEN'
65
+ end
66
+ end
67
+
68
+ it 'should get default Service' do
69
+ service = SmsBroker.service
70
+
71
+ expect(service.client).to be_a SmsBroker::Client::Nexmo
72
+ end
73
+
74
+ it 'should get custom Service' do
75
+ service = SmsBroker.service(:twilio)
76
+
77
+ expect(service.client).to be_a SmsBroker::Client::Twilio
78
+ end
79
+
80
+ end
81
+
82
+ context 'invalid configs' do
83
+
84
+ it 'should return error about available services' do
85
+ setup = SmsBroker.setup do |config|
86
+ config.services ['nexmo', 'twilio']
87
+
88
+ config.default_service 'nexmo'
89
+ end
90
+
91
+ expect(setup.valid?).to eq(false)
92
+ expect(setup.errors).to eq \
93
+ services_setups: [
94
+ 'all services must be setup'
95
+ ]
96
+ end
97
+
98
+ it 'should return error for not having services' do
99
+ setup = SmsBroker.setup do |config|
100
+ config.services []
101
+ end
102
+
103
+ expect(setup.valid?).to eq(false)
104
+
105
+ expect(setup.errors[:services]).to \
106
+ include('cannot have length less than 1')
107
+ end
108
+
109
+ it 'should return error default_service' do
110
+ setup = SmsBroker.setup do |config|
111
+ config.services ['nexmo', 'twilio']
112
+
113
+ config.default_service 'nope'
114
+ end
115
+
116
+ expect(setup.valid?).to eq(false)
117
+
118
+ expect(setup.errors[:default_service]).to \
119
+ include("must be within [\"nexmo\", \"twilio\"]")
120
+ end
121
+
122
+ context 'setup!' do
123
+
124
+ it 'should raise exception for invalid setup' do
125
+ expect {
126
+ SmsBroker.setup! do |config|
127
+ config.services ['nexmo', 'twilio']
128
+ config.default_service 'nope'
129
+ end
130
+ }.to raise_error(SmsBroker::Exceptions::InvalidSetup)
131
+ end
132
+
133
+ it 'should return error for missing required service setup' do
134
+ expect {
135
+ SmsBroker.setup! do |config|
136
+ config.default_service 'nexmo'
137
+
138
+ config.nexmo_setup \
139
+ not_exists: 'key'
140
+ end
141
+ }.to raise_error(SmsBroker::Exceptions::InvalidSetup)
142
+ end
143
+
144
+ end
145
+
146
+ end
147
+
148
+ end
149
+
150
+ it 'should respond_to :message' do
151
+ expect(SmsBroker.respond_to?(:message)).to eq(true)
152
+ end
153
+
154
+ it 'should raise InvalidSetup for service not being setup' do
155
+ SmsBroker.clear_setup
156
+
157
+ expect{ SmsBroker::Service.get(:twilio) }.to \
158
+ raise_error SmsBroker::Exceptions::InvalidSetup
159
+ end
160
+
161
+ end
@@ -0,0 +1,145 @@
1
+ describe SmsBroker do
2
+
3
+ context 'SmsBroker' do
4
+
5
+ let(:text_message) { 'Hello World' }
6
+
7
+ context 'Invalid data when trying to deliver' do
8
+
9
+ before(:all) do
10
+ SmsBroker.clear_setup
11
+
12
+ SmsBroker.setup do |config|
13
+ config.services ['twilio']
14
+
15
+ config.default_service 'twilio'
16
+
17
+ config.twilio_setup \
18
+ phone_number: '15005550001',
19
+ account_sid: ENV['TWILIO_ACCOUNT_SID'],
20
+ auth_token: ENV['TWILIO_AUTH_TOKEN']
21
+ end
22
+ end
23
+
24
+ it 'should return error for missing number' do
25
+ response = SmsBroker.service.message(text_message).to(nil).deliver
26
+
27
+ expect(response.success?).to eq(false)
28
+ expect(response.serialized[:errors][:to]).to include("is required")
29
+ end
30
+
31
+ it 'should return error for missing message' do
32
+ response = SmsBroker.service.message(nil).to(nil).deliver
33
+
34
+ expect(response.success?).to eq(false)
35
+ expect(response.serialized[:errors][:message]).to include("is required")
36
+ end
37
+
38
+ it 'should return error for invalid message' do
39
+ message_160 = "Lorem Ipsum is simply dummy text of the printing and " \
40
+ "typesetting industry. Lorem Ipsum has been the " \
41
+ "industry's standard dummy text ever since the 1500s, when an"
42
+
43
+ response = \
44
+ SmsBroker.service.message(message_160).to('44123457891').deliver
45
+
46
+ expect(response.success?).to eq(false)
47
+ expect(response.serialized[:errors][:message]).to \
48
+ include("cannot have length greater than 140")
49
+ end
50
+
51
+ end
52
+
53
+ context 'Invalid setup when trying to deliver' do
54
+
55
+ before(:all) do
56
+ SmsBroker.clear_setup
57
+
58
+ @setu = SmsBroker.setup do |config|
59
+ config.services ['nexmo']
60
+
61
+ config.default_service 'nexmo'
62
+
63
+ config.nexmo_setup \
64
+ key: ENV['NEXMO_API_KEY'],
65
+ sender_id: ENV['NEXMO_SENDER_ID'],
66
+ phone_number: ENV['NEXMO_PHONE_NUMBER']
67
+ # secret: ENV['NEXMO_API_SECRET']
68
+ end
69
+ end
70
+
71
+ it 'should return error for missing number' do
72
+ expect {
73
+ SmsBroker.service.message(text_message).to('44123457891').deliver
74
+ }.to raise_error SmsBroker::Exceptions::InvalidService
75
+ end
76
+
77
+ end
78
+
79
+ context 'Valid real calls' do
80
+
81
+ before(:all) do
82
+ SmsBroker.clear_setup
83
+
84
+ SmsBroker.setup do |config|
85
+ config.services ['nexmo', 'twilio']
86
+
87
+ config.default_service 'nexmo'
88
+
89
+ config.nexmo_setup \
90
+ key: ENV['NEXMO_API_KEY'],
91
+ secret: ENV['NEXMO_API_SECRET'],
92
+ sender_id: ENV['NEXMO_SENDER_ID'],
93
+ phone_number: ENV['NEXMO_PHONE_NUMBER']
94
+
95
+ config.twilio_setup \
96
+ sender_id: ENV['TWILIO_LIVE_SENDER_ID'],
97
+ auth_token: ENV['TWILIO_LIVE_AUTH_TOKEN'],
98
+ account_sid: ENV['TWILIO_LIVE_ACCOUNT_SID'],
99
+ phone_number: ENV['TWILIO_LIVE_PHONE_NUMBER']
100
+ end
101
+ end
102
+
103
+ before(:all) do
104
+ unless ENV['REAL_PHONE_NUMBER']
105
+ skip "REAL_PHONE_NUMBER env var is required to run this spec"
106
+ end
107
+
108
+ WebMock.allow_net_connect!
109
+ end
110
+
111
+ after(:all) do
112
+ WebMock.disable_net_connect!
113
+ end
114
+
115
+ context 'Nexmo' do
116
+
117
+ it "should successfuly send message" do
118
+ message = \
119
+ SmsBroker.service(:nexmo).message('test').to(ENV['REAL_PHONE_NUMBER'])
120
+
121
+ response = message.deliver
122
+
123
+ expect(response.success?).to eq true
124
+ end
125
+
126
+ end
127
+
128
+ context 'Twillio' do
129
+
130
+ it "should successfuly send message" do
131
+ message = \
132
+ SmsBroker.service(:twilio).message('test').to(ENV['REAL_PHONE_NUMBER'])
133
+
134
+ response = message.deliver
135
+
136
+ expect(response.success?).to eq true
137
+ end
138
+
139
+ end
140
+
141
+ end
142
+
143
+ end
144
+
145
+ end
@@ -0,0 +1,122 @@
1
+ describe SmsBroker do
2
+
3
+ context 'Twilio' do
4
+
5
+ context '#send_message' do
6
+
7
+ let(:text_message) { 'Hello World' }
8
+ let(:from_phone) { ENV['TWILIO_PHONE_NUMBER'] }
9
+ let(:sender_id) { ENV['TWILIO_SENDER_ID'] }
10
+
11
+ before(:each) do
12
+ SmsBroker.clear_setup
13
+ end
14
+
15
+ def send_message(text, to)
16
+ WebMock.allow_net_connect!
17
+
18
+ response = SmsBroker.service.message(text).to(to).deliver
19
+
20
+ WebMock.disable_net_connect!
21
+
22
+ response
23
+ end
24
+
25
+ context 'valid' do
26
+
27
+ it 'should send message with success' do
28
+ SmsBroker.setup do |config|
29
+ config.services ['twilio']
30
+
31
+ config.default_service 'twilio'
32
+
33
+ config.twilio_setup \
34
+ phone_number: from_phone,
35
+ account_sid: ENV['TWILIO_ACCOUNT_SID'],
36
+ auth_token: ENV['TWILIO_AUTH_TOKEN']
37
+ end
38
+
39
+ response = send_message(text_message, '15005550006')
40
+
41
+ expect(response.service).to eq(:twilio)
42
+ expect(response.success?).to eq(true)
43
+ expect(response.message_id).not_to eq(nil)
44
+ end
45
+
46
+ context 'with sender_id' do
47
+
48
+ before(:each) do
49
+ SmsBroker.setup do |config|
50
+ config.services ['twilio']
51
+
52
+ config.default_service 'twilio'
53
+
54
+ config.twilio_setup \
55
+ phone_number: '15005550001',
56
+ account_sid: ENV['TWILIO_ACCOUNT_SID'],
57
+ auth_token: ENV['TWILIO_AUTH_TOKEN']
58
+ end
59
+ end
60
+
61
+ it 'should return error for invalid sender_id' do
62
+ response = send_message(text_message, '15005550006')
63
+
64
+ expect(response.service).to eq(:twilio)
65
+
66
+ expect(response.success?).to eq(false)
67
+
68
+ expect(response.serialized[:errors].keys).to include('21212')
69
+ # if the code is 21212 and message includes the phone_number,
70
+ # it means that it tried with sender_id and failed
71
+ expect(response.serialized[:errors]['21212'][0]).to \
72
+ include("The 'From' number 15005550001 is not a valid")
73
+ end
74
+
75
+ end
76
+
77
+ end
78
+
79
+ context 'invalid' do
80
+
81
+ it 'should return error for missing required data' do
82
+ SmsBroker.setup do |config|
83
+ config.services ['twilio']
84
+
85
+ config.default_service 'twilio'
86
+
87
+ config.twilio_setup \
88
+ phone_number: '15005550001',
89
+ account_sid: ENV['TWILIO_ACCOUNT_SID'],
90
+ auth_token: ENV['TWILIO_AUTH_TOKEN']
91
+ end
92
+
93
+ response = SmsBroker.message(text_message).deliver
94
+
95
+ expect(response.serialized[:errors][:to]).to include('is required')
96
+ end
97
+
98
+ it 'should return error for invalid from phone' do
99
+ SmsBroker.setup do |config|
100
+ config.services ['twilio']
101
+
102
+ config.default_service 'twilio'
103
+
104
+ config.twilio_setup \
105
+ phone_number: '15005550001',
106
+ account_sid: ENV['TWILIO_ACCOUNT_SID'],
107
+ auth_token: ENV['TWILIO_AUTH_TOKEN']
108
+ end
109
+
110
+ response = send_message(text_message, '15005550006')
111
+
112
+ expect(response.success?).to eq(false)
113
+ expect(response.serialized.length).to be > 0
114
+ end
115
+
116
+ end
117
+
118
+ end
119
+
120
+ end
121
+
122
+ end
@@ -0,0 +1,29 @@
1
+ require 'pry'
2
+ require 'yaml'
3
+ require 'simplecov'
4
+ require 'codeclimate-test-reporter'
5
+
6
+ SimpleCov.start do
7
+ formatter SimpleCov::Formatter::MultiFormatter.new [
8
+ SimpleCov::Formatter::HTMLFormatter,
9
+ CodeClimate::TestReporter::Formatter
10
+ ]
11
+ end
12
+
13
+ # load service_keys.yml to ENV
14
+ yml_file = File.expand_path('../support/services_keys.yml', __FILE__)
15
+
16
+ YAML.load(File.read(yml_file)).each do |key, value|
17
+ ENV[key] = value
18
+ end
19
+
20
+ require 'sms_broker'
21
+ require 'webmock/rspec'
22
+
23
+ require 'support/nexmo_helpers'
24
+
25
+ RSpec.configure do |config|
26
+
27
+ config.include NexmoHelpers
28
+
29
+ end