mock-twilio 0.1.0 → 0.3.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.
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.