mock-twilio 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ab342d529e8d1886517cdffe112de027d4faa800e999f1761d70cacf91da958
4
- data.tar.gz: 42f3e99d12fe4b0e88160d52437a32c8cf20786abaebb32a4ad084579a223d4f
3
+ metadata.gz: 2832d75e6a41828ad36e39908bc9316a8d851ced711843a9ec3142e46ac65a04
4
+ data.tar.gz: d20f52b78ef3d357e1210100b874ab08e35429993ee3c7499077267e40f25733
5
5
  SHA512:
6
- metadata.gz: a74c263e59ca0f944ef427387e60c6ec1d9a30e0e02d0583b1993171f286f58e3b6178cf9eed13fa0db68c88e2071f4512e6d18cbace5d04120c51c7bbb24759
7
- data.tar.gz: b1782b5d6da621259f3b3d0633623b1c9cfed90993ff613f73485bf169f22317da1396f73ca1f7102fa7456261a8d2752272ac6f44f10c2452cc9f669b2660cb
6
+ metadata.gz: 73a12decb37e2c63b6ab66d2d74fa49d9a281bd8a4391ed321a44f4dfb83ae81946a80e1d26f18903185e5393267714184bab959d8b073dd52d2dd8196aed0d1
7
+ data.tar.gz: cbdabf698e265893034d10ff001d7ae01ca035e8da18af469b1fbb9c399425e509bc3d49be40c6cb72b418ea86dc53f2336cc8cc75dce4cc6ecc2e262912a84c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [0.3.0] - 2024-06-24
2
+ - Support Calls service
3
+ - Support Conferences service
4
+ - Support Webhooks CallStatusUpdates, Conferences and Calls
5
+
6
+ ## [0.2.0] - 2024-06-09
7
+ - Support MessageSid SMS and MMS
8
+ - Support Webhooks::Messages SMS and MMS
9
+
1
10
  ## [0.1.0] - 2024-05-29
2
11
 
3
12
  - Initial release
data/Gemfile CHANGED
@@ -8,3 +8,6 @@ gemspec
8
8
  gem "rake", "~> 13.0"
9
9
 
10
10
  gem "minitest", "~> 5.0"
11
+ gem 'simplecov', require: false, group: :test
12
+ gem "webmock"
13
+ gem "pry"
data/README.md CHANGED
@@ -1,19 +1,15 @@
1
1
  ## Mock::Twilio::Client
2
+ [![Gem Version](https://badge.fury.io/rb/mock-twilio.svg)](https://badge.fury.io/rb/mock-twilio)
3
+ ![mock-twilio](https://github.com/schoolstatus/mock-twilio/actions/workflows/ruby.yml/badge.svg)
2
4
 
3
5
  This is a SchoolStatus implementation to mock twilio client to perform requests to [twilio-oai](https://github.com/twilio/twilio-oai)
4
6
 
5
7
 
6
8
  # Installation
7
9
 
8
- To install using [Bundler][bundler] grab the latest stable version:
10
+ To install using bundler grab the latest stable version:
9
11
 
10
12
  ```ruby
11
- gem 'mock-twilio', '~> 0.1.0'
12
- ```
13
-
14
- To manually install `twilio-ruby` via [Rubygems][rubygems] simply gem install:
15
-
16
- ```bash
17
13
  gem install mock-twilio
18
14
  ```
19
15
 
@@ -31,7 +27,18 @@ OR
31
27
  - `proxy_protocol = http`
32
28
 
33
29
  ## How to use
30
+ Initializer sample
31
+ ```ruby
32
+ Mock::Twilio.configure do |config|
33
+ config.host = "http://shunkan-ido-service"
34
+ config.forwarded_host = "shunkan-ido-service"
35
+ config.port = "3000"
36
+ config.proto = "http"
37
+ end
34
38
 
39
+ ```
40
+
41
+ Example
35
42
  ```ruby
36
43
  export TWILIO_ACCOUNT_SID=ACFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
37
44
  export TWILIO_API_KEY=SKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
@@ -42,6 +49,11 @@ client = Twilio::REST::Client.new(nil, nil, nil, nil, mock_client)
42
49
  client.messages.create(to: "+593978613041", body: "RB This is the ship that made the Kesssssel Run in fourteen parsecs?", from: "+13212855389")
43
50
  ```
44
51
 
52
+ ## Run tests
53
+ ```unix
54
+ rake test
55
+ ```
56
+
45
57
  ## Swagger - OpenApi Issues
46
58
 
47
59
  - Array and Boolean validations due open api formats, ie params as `status_callback_event`, `early_media`. Validations removed for them on json files.
data/Rakefile CHANGED
@@ -7,6 +7,7 @@ Rake::TestTask.new(:test) do |t|
7
7
  t.libs << "test"
8
8
  t.libs << "lib"
9
9
  t.test_files = FileList["test/**/test_*.rb"]
10
+ t.warning = false
10
11
  end
11
12
 
12
13
  task default: :test
@@ -7,7 +7,7 @@ module Mock
7
7
  # client.messages.create(to: "+593978613041", body: "RB This is the ship that made the Kesssssel Run in fourteen parsecs?", from: "+13212855389")
8
8
  class Client
9
9
  attr_accessor :adapter
10
- attr_reader :timeout, :last_response, :last_request
10
+ attr_reader :timeout, :last_response, :last_request, :proxy_addr, :proxy_port, :proxy_prot
11
11
 
12
12
  def initialize(proxy_prot = nil, proxy_addr = nil, proxy_port = nil, timeout: nil)
13
13
  @proxy_prot = proxy_prot || 'http'
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "schemas/api_2010"
4
+ require_relative "schemas/messaging_v1"
5
+
3
6
  module Mock
4
7
  module Twilio
5
8
  class Decorator
@@ -11,9 +14,15 @@ module Mock
11
14
  class << self
12
15
  def call(body, request)
13
16
  body = JSON.parse(body)
17
+
18
+ case body["status"]
19
+ when 400..600
20
+ return body
21
+ end
22
+
14
23
  schema = url_from(body, request)
15
- # return body decorataor if needed
16
- return ENDPOINTS[schema].decorate(body) if schema
24
+ # return body decorate if needed
25
+ return ENDPOINTS[schema].for(body, request) if schema
17
26
 
18
27
  body
19
28
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mock
4
+ module Twilio
5
+ module Decorators
6
+ module Api2010
7
+ class Calls
8
+ class << self
9
+ def decorate(body, request)
10
+ body["date_updated"] = Time.current.rfc2822 if body["date_updated"]
11
+ body["date_sent"] = Time.current.rfc2822 if body["date_sent"]
12
+ body["date_created"] = Time.current.rfc2822 if body["date_created"]
13
+ body["start_time"] = Time.current.rfc2822 if body["start_time"]
14
+ body["end_time"] = Time.current.rfc2822 if body["end_time"]
15
+
16
+ call_sid(body, request) if body["sid"]
17
+ phone_number_sid(body, request) if body["phone_number_sid"]
18
+ body["direction"] = "outbound-api" if body["direction"]
19
+ body["api_version"] = "2010-04-01" if body["api_version"]
20
+ body["to"] = request.data['To'] if body["to"]
21
+ body["from"] = request.data['From'] if body["from"]
22
+
23
+ body
24
+ end
25
+
26
+ def call_sid(body, request)
27
+ prefix = "CA"
28
+ sid = prefix + SecureRandom.hex(16)
29
+ scheduler = Rufus::Scheduler.new
30
+ scheduler.in '2s' do
31
+ conference_uuid = request.data["Url"].split("conference_uuid=").last
32
+ response = Mock::Twilio::Webhooks::CallStatusUpdates.trigger(sid, conference_uuid)
33
+
34
+ conference_response = if response.status == 200
35
+ twiMl_xml = Nokogiri::XML response.body
36
+ friendly_name = twiMl_xml.at_xpath('//Dial').at_xpath('//Conference').children.text
37
+ Mock::Twilio::Webhooks::Conferences.trigger(friendly_name)
38
+ end
39
+
40
+ Mock::Twilio::Webhooks::Calls.trigger(sid) if conference_response.status == 200
41
+ end
42
+ body["sid"] = sid
43
+ end
44
+
45
+ def phone_number_sid(body, request)
46
+ prefix = "PN"
47
+ sid = prefix + SecureRandom.hex(16)
48
+ body["phone_number_sid"] = sid
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mock
4
+ module Twilio
5
+ module Decorators
6
+ module Api2010
7
+ class ConferencesParticipantsCreate
8
+ class << self
9
+ def decorate(body, request)
10
+ body["date_updated"] = Time.current.rfc2822 if body["date_updated"]
11
+ body["date_created"] = Time.current.rfc2822 if body["date_created"]
12
+ body["account_sid"] = ::Twilio.account_sid if body["account_sid"]
13
+ body["label"] = "Mock Customer" if body["label"]
14
+ body["status"] = "initiated" if body["status"]
15
+
16
+ parse_call_sid(body, request) if body["call_sid"]
17
+ parse_conference_sid(body, request) if body["conference_sid"]
18
+
19
+ body
20
+ end
21
+
22
+ def parse_call_sid(body, request)
23
+ prefix = "CA"
24
+ call_sid = prefix + SecureRandom.hex(16)
25
+ body["call_sid"] = call_sid
26
+ end
27
+
28
+ def parse_conference_sid(body, request)
29
+ uri = URI(request.url)
30
+ conference_sid = uri.path.split('/')[5]
31
+ body["conference_sid"] = conference_sid
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mock
4
+ module Twilio
5
+ module Decorators
6
+ module Api2010
7
+ class ConferencesParticipantsUpdate
8
+ class << self
9
+ def decorate(body, request)
10
+ body["date_updated"] = Time.current.rfc2822 if body["date_updated"]
11
+ body["date_created"] = Time.current.rfc2822 if body["date_created"]
12
+ body["account_sid"] = ::Twilio.account_sid if body["account_sid"]
13
+ body["label"] = "Mock Customer" if body["label"]
14
+ body["status"] = "complete" if body["status"]
15
+
16
+ parse_call_sid(body, request) if body["call_sid"]
17
+ parse_conference_sid(body, request) if body["conference_sid"]
18
+
19
+ body
20
+ end
21
+
22
+ def parse_call_sid(body, request)
23
+ uri = URI(request.url)
24
+ call_sid = uri.path.split('/')[7].split('.').first
25
+ body["call_sid"] = call_sid
26
+ end
27
+
28
+ def parse_conference_sid(body, request)
29
+ uri = URI(request.url)
30
+ conference_sid = uri.path.split('/')[5]
31
+ body["conference_sid"] = conference_sid
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mock
4
+ module Twilio
5
+ module Decorators
6
+ module Api2010
7
+ class Messages
8
+ class << self
9
+ def decorate(body, request)
10
+ body["date_updated"] = Time.current.rfc2822 if body["date_updated"]
11
+ body["date_sent"] = Time.current.rfc2822 if body["date_sent"]
12
+ body["date_created"] = Time.current.rfc2822 if body["date_created"]
13
+ body["start_time"] = Time.current.rfc2822 if body["start_time"]
14
+ body["end_time"] = Time.current.rfc2822 if body["end_time"]
15
+
16
+ message_sid(body, request) if body["sid"]
17
+ pagination(body) if body["available_phone_numbers"]
18
+
19
+ body
20
+ end
21
+
22
+ def pagination(body)
23
+ # Params returned in mock_server but not on real twilio request for the moment.
24
+ # Not needed for us now.
25
+ PAGES_KEYS.each do |key|
26
+ body.delete(key) if body[key]
27
+ end
28
+ end
29
+
30
+ def message_sid(body, request)
31
+ prefix = request.data["MediaUrl"] ? "MM" : "SM"
32
+ sid = prefix + SecureRandom.hex(16)
33
+ scheduler = Rufus::Scheduler.new
34
+ scheduler.in '2s' do
35
+ Mock::Twilio::Webhooks::Messages.trigger(sid)
36
+ end
37
+ body["sid"] = sid
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,10 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../decorators/api_2010/messages"
4
+ require_relative "../decorators/api_2010/calls"
5
+ require_relative "../decorators/api_2010/conferences_participants_update"
6
+ require_relative "../decorators/api_2010/conferences_participants_create"
7
+
3
8
  module Mock
4
9
  module Twilio
5
10
  module Schemas
6
11
  class Api2010
7
12
  class << self
13
+ RESOURCES = {
14
+ messages: Mock::Twilio::Decorators::Api2010::Messages,
15
+ calls: Mock::Twilio::Decorators::Api2010::Calls,
16
+ conferences_participants_update: Mock::Twilio::Decorators::Api2010::ConferencesParticipantsUpdate,
17
+ conferences_participants_create: Mock::Twilio::Decorators::Api2010::ConferencesParticipantsCreate,
18
+ }
19
+
8
20
  PAGES_KEYS = [
9
21
  "end",
10
22
  "first_page_uri",
@@ -19,22 +31,18 @@ module Mock
19
31
  "uri"
20
32
  ].freeze
21
33
 
22
- def decorate(body)
23
- body["date_updated"] = Time.current.rfc2822 if body["date_updated"]
24
- body["date_sent"] = Time.current.rfc2822 if body["date_sent"]
25
- body["date_created"] = Time.current.rfc2822 if body["date_created"]
26
- body["start_time"] = Time.current.rfc2822 if body["start_time"]
27
- body["end_time"] = Time.current.rfc2822 if body["end_time"]
28
-
29
- pagination(body) if body["available_phone_numbers"]
30
- body
31
- end
34
+ def for(body, request)
35
+ url = request.url.split(request.host).last
32
36
 
33
- def pagination(body)
34
- # Params returned in mock_server but not on real twilio request for the moment.
35
- # Not needed for us now.
36
- PAGES_KEYS.each do |key|
37
- body.delete(key) if body[key]
37
+ case url
38
+ when %r{\/2010-04-01/Accounts/[A-Za-z0-9]+/Messages.json}
39
+ RESOURCES[:messages].decorate(body, request)
40
+ when %r{\/2010-04-01/Accounts/[A-Za-z0-9]+/Calls.json}
41
+ RESOURCES[:calls].decorate(body, request)
42
+ when %r{\/2010-04-01/Accounts/[A-Za-z0-9]+/Conferences/[A-Za-z0-9]+/Participants/[A-Za-z0-9]+.json}
43
+ RESOURCES[:conferences_participants_update].decorate(body, request)
44
+ when %r{\/2010-04-01/Accounts/[A-Za-z0-9]+/Conferences/[A-Za-z0-9]+/Participants.json}
45
+ RESOURCES[:conferences_participants_create].decorate(body, request)
38
46
  end
39
47
  end
40
48
  end
@@ -5,7 +5,7 @@ module Mock
5
5
  module Schemas
6
6
  class MessagingV1
7
7
  class << self
8
- def decorate(body)
8
+ def decorate(body, request)
9
9
  # Params for twilio pagination, needed for twilio-ruby serializers and absolute paths
10
10
  body["meta"]["key"] = "phone_numbers" if body["meta"]
11
11
  body["meta"]["page_size"] = 20 if body["meta"]
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mock
4
+ module Twilio
5
+ module Util
6
+ class Configuration
7
+ attr_accessor :host, :forwarded_host, :port, :proto
8
+
9
+ def host=(value)
10
+ @host = value
11
+ end
12
+
13
+ def forwarded_host=(value)
14
+ @forwarded_host = value
15
+ end
16
+
17
+ def port=(value)
18
+ @port = value
19
+ end
20
+
21
+ def proto=(value)
22
+ @proto = value
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Mock
4
4
  module Twilio
5
- VERSION = "0.1.0"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mock
4
+ module Twilio
5
+ class WebhooksClient
6
+ attr_accessor :adapter
7
+ attr_reader :timeout, :last_request
8
+
9
+ def initialize(timeout: nil)
10
+ @timeout = timeout
11
+ @adapter = Faraday.default_adapter
12
+ end
13
+
14
+ def _request(request)
15
+ @connection = Faraday.new(url: request.host + ":" + request.port.to_s, ssl: { verify: true }) do |f|
16
+ f.options.params_encoder = Faraday::FlatParamsEncoder
17
+ f.request :url_encoded
18
+ f.adapter @adapter
19
+ f.headers = request.headers
20
+ f.request(:authorization, :basic, request.auth[0], request.auth[1])
21
+
22
+ f.options.open_timeout = request.timeout || @timeout
23
+ f.options.timeout = request.timeout || @timeout
24
+ end
25
+
26
+ response = @connection.send(request.method.downcase.to_sym,
27
+ request.url,
28
+ request.method == "GET" ? request.params : request.data)
29
+
30
+ if response.body && !response.body.empty?
31
+ object = response.body
32
+ elsif response.status == 400
33
+ object = { message: "Bad request", code: 400 }.to_json
34
+ end
35
+
36
+ response
37
+ end
38
+
39
+ def request(host, port, method, url, params = {}, data = {}, headers = {}, auth = nil, timeout = nil)
40
+ request = ::Twilio::Request.new(host, port, method, url, params, data, headers, auth, timeout)
41
+ _request(request)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mock
4
+ module Twilio
5
+ module Webhooks
6
+ class RestError < StandardError
7
+ end
8
+ class Base
9
+ DELAY = [0.5, 0.8]
10
+
11
+ def self.build_signature_for_request(request_url, params)
12
+ validator = ::Twilio::Security::RequestValidator.new(::Twilio.auth_token)
13
+ validator.build_signature_for(request_url, params)
14
+ end
15
+
16
+ def self.twilio_client
17
+ ::Twilio::REST::Client.new
18
+ end
19
+
20
+ def self.webhook_client
21
+ Mock::Twilio::WebhooksClient.new
22
+ end
23
+
24
+ def self.auth_twilio
25
+ [twilio_client.account_sid, twilio_client.auth_token]
26
+ end
27
+
28
+ def self.headers
29
+ {
30
+ 'X-Forwarded-Proto': Mock::Twilio.proto,
31
+ 'Host': Mock::Twilio.forwarded_host
32
+ }
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mock
4
+ module Twilio
5
+ module Webhooks
6
+ class CallStatusUpdates < Base
7
+ URL = "/api/v1/twilio_calls/voice_responses"
8
+
9
+ def self.trigger(sid, conference_uuid)
10
+ # Wait simulation from twilio
11
+ sleep DELAY.sample
12
+
13
+ request_url = Mock::Twilio.proto + "://" + Mock::Twilio.forwarded_host + URL
14
+
15
+ data = call_status_updates_data(sid, conference_uuid)
16
+
17
+ signature = build_signature_for_request(request_url, data)
18
+
19
+ response = webhook_client.request(Mock::Twilio.host,
20
+ Mock::Twilio.port,
21
+ 'POST',
22
+ URL,
23
+ nil,
24
+ data,
25
+ headers.merge!({ 'X-Twilio-Signature': signature }),
26
+ auth_twilio,
27
+ nil)
28
+ case response.status
29
+ when 200..204
30
+ response
31
+ when 400..600
32
+ raise Webhooks::RestError, response.body
33
+ end
34
+ end
35
+
36
+ def self.call_status_updates_data(sid, conference_uuid)
37
+ {
38
+ :AccountSid=> twilio_client.account_sid,
39
+ :ApiVersion=> "2010-04-01",
40
+ :CallbackSource=> "call-progress-events",
41
+ :CallDuration=> "0",
42
+ :Called=> "+18222222222",
43
+ :CalledCity=> "TAMPA",
44
+ :CalledCountry=> "US",
45
+ :CalledState=> "FL",
46
+ :CalledZip=> "33605",
47
+ :Caller=> "+18111111111",
48
+ :CallerCity=> "no value",
49
+ :CallerCountry=> "US",
50
+ :CallerState=> "CA",
51
+ :CallerZip=> "no value",
52
+ :CallSid=> sid,
53
+ :CallStatus=> "in-progress",
54
+ :Direction=> "outbound-api",
55
+ :Duration=> "0",
56
+ :From=> "+18111111111",
57
+ :FromCity=> "no value",
58
+ :FromCountry=> "US",
59
+ :FromState=> "CA",
60
+ :FromZip=> "no value",
61
+ :SequenceNumber=> "2",
62
+ :SipResponseCode=> "487",
63
+ :Timestamp=> "2024-06-17 16:49:31 UTC",
64
+ :To=> "+18222222222",
65
+ :ToCity=> "TAMPA",
66
+ :ToCountry=> "US",
67
+ :ToState=> "FL",
68
+ :ToZip=> "33605",
69
+ :StirStatus=> "B",
70
+ :StirVerstat=> "TN-Validation-Passed-B",
71
+ :AnsweredBy=> "unknown",
72
+ :conference_uuid=> conference_uuid
73
+ }
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mock
4
+ module Twilio
5
+ module Webhooks
6
+ class Calls < Base
7
+ URL = "/api/v1/twilio_calls/participant_status_changes"
8
+
9
+ def self.trigger(sid)
10
+ # Wait simulation from twilio
11
+ sleep DELAY.sample
12
+
13
+ request_url = Mock::Twilio.proto + "://" + Mock::Twilio.forwarded_host + URL
14
+
15
+ data = call_data(sid)
16
+
17
+ signature = build_signature_for_request(request_url, data)
18
+
19
+ response = webhook_client.request(Mock::Twilio.host,
20
+ Mock::Twilio.port,
21
+ 'POST',
22
+ URL,
23
+ nil,
24
+ data,
25
+ headers.merge!({ 'X-Twilio-Signature': signature }),
26
+ auth_twilio,
27
+ nil)
28
+ case response.status
29
+ when 200..204
30
+ response
31
+ when 400..600
32
+ raise Webhooks::RestError, response.body
33
+ end
34
+ end
35
+
36
+ def self.call_data(sid)
37
+ {
38
+ :AccountSid=> twilio_client.account_sid,
39
+ :ApiVersion=> "2010-04-01",
40
+ :CallbackSource=> "call-progress-events",
41
+ :CallDuration=> "0",
42
+ :Called=> "+18222222222",
43
+ :CalledCity=> "TAMPA",
44
+ :CalledCountry=> "US",
45
+ :CalledState=> "FL",
46
+ :CalledZip=> "33605",
47
+ :Caller=> "+18111111111",
48
+ :CallerCity=> "no value",
49
+ :CallerCountry=> "US",
50
+ :CallerState=> "CA",
51
+ :CallerZip=> "no value",
52
+ :CallSid=> sid,
53
+ :CallStatus=> "in-progress",
54
+ :Direction=> "outbound-api",
55
+ :Duration=> "0",
56
+ :From=> "+18111111111",
57
+ :FromCity=> "no value",
58
+ :FromCountry=> "US",
59
+ :FromState=> "CA",
60
+ :FromZip=> "no value",
61
+ :SequenceNumber=> "2",
62
+ :SipResponseCode=> "487",
63
+ :Timestamp=> "2024-06-17 16:49:31 UTC",
64
+ :To=> "+18222222222",
65
+ :ToCity=> "TAMPA",
66
+ :ToCountry=> "US",
67
+ :ToState=> "FL",
68
+ :ToZip=> "33605"
69
+ }
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mock
4
+ module Twilio
5
+ module Webhooks
6
+ class Conferences < Base
7
+ URL = "/api/v1/twilio_calls/conference_status_changes"
8
+
9
+ def self.trigger(friendly_name)
10
+ # Wait simulation from twilio
11
+ sleep DELAY.sample
12
+
13
+ request_url = Mock::Twilio.proto + "://" + Mock::Twilio.forwarded_host + URL
14
+
15
+ data = conference_data(friendly_name)
16
+
17
+ signature = build_signature_for_request(request_url, data)
18
+
19
+ response = webhook_client.request(Mock::Twilio.host,
20
+ Mock::Twilio.port,
21
+ 'POST',
22
+ URL,
23
+ nil,
24
+ data,
25
+ headers.merge!({ 'X-Twilio-Signature': signature }),
26
+ auth_twilio,
27
+ nil)
28
+
29
+ case response.status
30
+ when 200..204
31
+ response
32
+ when 400..600
33
+ raise Webhooks::RestError, response.body
34
+ end
35
+ end
36
+
37
+ def self.conference_data(friendly_name)
38
+ prefix = "CF"
39
+ sid = prefix + SecureRandom.hex(16)
40
+ {
41
+ :FriendlyName=> friendly_name,
42
+ :SequenceNumber=> "6",
43
+ :ConferenceSid=> sid,
44
+ :StatusCallbackEvent=> "conference-start",
45
+ :Timestamp=> "2024-06-17 16:49:31 UTC",
46
+ :AccountSid=> twilio_client.account_sid,
47
+ :Reason=> "Participant from mock twilio"
48
+ }
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mock
4
+ module Twilio
5
+ module Webhooks
6
+ class Messages < Base
7
+ URL = "/api/v1/twilio_requests/webhook_message_updates"
8
+
9
+ def self.trigger(sid)
10
+ # Wait simulation from twilio
11
+ sleep DELAY.sample
12
+
13
+ request_url = Mock::Twilio.proto + "://" + Mock::Twilio.forwarded_host + URL
14
+
15
+ data = { :MessageSid=>sid, :MessageStatus=>"delivered" }
16
+
17
+ signature = build_signature_for_request(request_url, data)
18
+
19
+ response = webhook_client.request(Mock::Twilio.host,
20
+ Mock::Twilio.port,
21
+ 'POST',
22
+ URL,
23
+ nil,
24
+ data,
25
+ headers.merge!({ 'X-Twilio-Signature': signature }),
26
+ auth_twilio,
27
+ nil)
28
+ case response.status
29
+ when 200..204
30
+ response
31
+ when 400..600
32
+ raise Webhooks::RestError, response.body
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
data/lib/mock/twilio.rb CHANGED
@@ -1,8 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rufus-scheduler"
4
+ require "active_support"
5
+ require "active_support/core_ext/time"
3
6
  require_relative "twilio/middleware/proxy"
4
- require_relative "twilio/schemas/api_2010"
5
- require_relative "twilio/schemas/messaging_v1"
7
+ require_relative "twilio/webhook_client"
8
+ require_relative "twilio/webhooks/base"
9
+ require_relative "twilio/webhooks/messages"
10
+ require_relative "twilio/webhooks/calls"
11
+ require_relative "twilio/webhooks/call_status_updates"
12
+ require_relative "twilio/webhooks/conferences"
13
+ require_relative "twilio/util/configuration"
6
14
  require_relative "twilio/client"
7
15
  require_relative "twilio/decorator"
8
16
  require_relative "twilio/response"
@@ -10,6 +18,18 @@ require_relative "twilio/version"
10
18
 
11
19
  module Mock
12
20
  module Twilio
13
- class Error < StandardError; end
21
+ extend SingleForwardable
22
+
23
+ def_delegators :configuration, :host, :forwarded_host, :port, :proto
24
+
25
+ def self.configure(&block)
26
+ yield configuration
27
+ end
28
+
29
+ def self.configuration
30
+ @configuration ||= Util::Configuration.new
31
+ end
32
+
33
+ private_class_method :configuration
14
34
  end
15
35
  end
metadata CHANGED
@@ -1,29 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mock-twilio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SchoolStatus Platform Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-10 00:00:00.000000000 Z
11
+ date: 2024-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: '2.7'
19
+ version: 2.9.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: '2.7'
26
+ version: 2.9.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: rufus-scheduler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 3.9.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 3.9.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: twilio-ruby
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 6.7.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 6.7.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 7.1.3.4
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 7.1.3.4
27
69
  description: This repository contains Mock::Twilio::Client for Twilio's API.
28
70
  email:
29
71
  executables: []
@@ -38,19 +80,30 @@ files:
38
80
  - lib/mock/twilio.rb
39
81
  - lib/mock/twilio/client.rb
40
82
  - lib/mock/twilio/decorator.rb
83
+ - lib/mock/twilio/decorators/api_2010/calls.rb
84
+ - lib/mock/twilio/decorators/api_2010/conferences_participants_create.rb
85
+ - lib/mock/twilio/decorators/api_2010/conferences_participants_update.rb
86
+ - lib/mock/twilio/decorators/api_2010/messages.rb
41
87
  - lib/mock/twilio/middleware/proxy.rb
42
88
  - lib/mock/twilio/response.rb
43
89
  - lib/mock/twilio/schemas/api_2010.rb
44
90
  - lib/mock/twilio/schemas/messaging_v1.rb
91
+ - lib/mock/twilio/util/configuration.rb
45
92
  - lib/mock/twilio/version.rb
93
+ - lib/mock/twilio/webhook_client.rb
94
+ - lib/mock/twilio/webhooks/base.rb
95
+ - lib/mock/twilio/webhooks/call_status_updates.rb
96
+ - lib/mock/twilio/webhooks/calls.rb
97
+ - lib/mock/twilio/webhooks/conferences.rb
98
+ - lib/mock/twilio/webhooks/messages.rb
46
99
  - sig/mock/twilio.rbs
47
100
  homepage: https://github.com/schoolstatus/mock-twilio
48
101
  licenses:
49
102
  - MIT
50
103
  metadata:
51
104
  homepage_uri: https://github.com/schoolstatus/mock-twilio
52
- source_code_uri: https://github.com/schoolstatus/mock-twilio.
53
- changelog_uri: https://github.com/schoolstatus/mock-twilio/CHANGELOG.md
105
+ source_code_uri: https://github.com/schoolstatus/mock-twilio
106
+ changelog_uri: https://github.com/schoolstatus/mock-twilio/blob/main/CHANGELOG.md
54
107
  post_install_message:
55
108
  rdoc_options: []
56
109
  require_paths:
@@ -66,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
66
119
  - !ruby/object:Gem::Version
67
120
  version: '0'
68
121
  requirements: []
69
- rubygems_version: 3.4.19
122
+ rubygems_version: 3.5.12
70
123
  signing_key:
71
124
  specification_version: 4
72
125
  summary: This repository contains Mock::Twilio::Client for Twilio's API.