M .rubocop.yml => .rubocop.yml +3 -0
@@ 45,6 45,9 @@ Layout/SpaceAroundEqualsInParameterDefault:
Layout/AccessModifierIndentation:
EnforcedStyle: outdent
+Layout/FirstParameterIndentation:
+ EnforcedStyle: consistent
+
Style/BlockDelimiters:
EnforcedStyle: braces_for_chaining
M Gemfile => Gemfile +2 -0
@@ 8,9 8,11 @@ gem "dhall"
gem "em-hiredis"
gem "em-http-request"
gem "em-pg-client", git: "https://github.com/royaltm/ruby-em-pg-client"
+gem "em-synchrony"
gem "em_promise.rb"
gem "eventmachine"
gem "money-open-exchange-rates"
+gem "ruby-bandwidth-iris"
group(:development) do
gem "pry-reload"
A lib/bandwidth_tn_order.rb => lib/bandwidth_tn_order.rb +87 -0
@@ 0,0 1,87 @@
+# frozen_string_literal: true
+
+require "forwardable"
+require "ruby-bandwidth-iris"
+Faraday.default_adapter = :em_synchrony
+
+class BandwidthTNOrder
+ def self.get(id)
+ EM.promise_fiber do
+ self.for(BandwidthIris::Order.get_order_response(
+ # https://github.com/Bandwidth/ruby-bandwidth-iris/issues/44
+ BandwidthIris::Client.new,
+ id
+ ))
+ end
+ end
+
+ def self.create(tel, name: "sgx-jmp order #{tel}")
+ bw_tel = tel.sub(/^\+?1?/, "")
+ EM.promise_fiber do
+ Received.new(BandwidthIris::Order.create(
+ name: name,
+ site_id: CONFIG[:bandwidth_site],
+ existing_telephone_number_order_type: {
+ telephone_number_list: { telephone_number: [bw_tel] }
+ }
+ ))
+ end
+ end
+
+ def self.for(bandwidth_order)
+ const_get(bandwidth_order.order_status.capitalize).new(bandwidth_order)
+ rescue NameError
+ new(bandwidth_order)
+ end
+
+ extend Forwardable
+ def_delegators :@order, :id
+
+ def initialize(bandwidth_order)
+ @order = bandwidth_order
+ end
+
+ def status
+ @order[:order_status]&.downcase&.to_sym
+ end
+
+ def error_description
+ @order[:error_list]&.dig(:error, :description)
+ end
+
+ def poll
+ raise "Unknown order status: #{status}"
+ end
+
+ class Received < BandwidthTNOrder
+ def status
+ :received
+ end
+
+ def poll
+ EM.promise_timer(1).then do
+ BandwidthTNOrder.get(id).then(&:poll)
+ end
+ end
+ end
+
+ class Complete < BandwidthTNOrder
+ def status
+ :complete
+ end
+
+ def poll
+ EMPromise.resolve(self)
+ end
+ end
+
+ class Failed < BandwidthTNOrder
+ def status
+ :failed
+ end
+
+ def poll
+ raise "Order failed: #{id} #{error_description}"
+ end
+ end
+end
A test/test_bandwidth_tn_order.rb => test/test_bandwidth_tn_order.rb +89 -0
@@ 0,0 1,89 @@
+# frozen_string_literal: true
+
+require "test_helper"
+require "bandwidth_tn_order"
+
+class BandwidthTNOrderTest < Minitest::Test
+ def test_for_received
+ order = BandwidthTNOrder.for(BandwidthIris::Order.new(
+ order_status: "RECEIVED"
+ ))
+ assert_kind_of BandwidthTNOrder::Received, order
+ end
+
+ def test_for_complete
+ order = BandwidthTNOrder.for(BandwidthIris::Order.new(
+ order_status: "COMPLETE"
+ ))
+ assert_kind_of BandwidthTNOrder::Complete, order
+ end
+
+ def test_for_failed
+ order = BandwidthTNOrder.for(BandwidthIris::Order.new(
+ order_status: "FAILED"
+ ))
+ assert_kind_of BandwidthTNOrder::Failed, order
+ end
+
+ def test_for_unknown
+ order = BandwidthTNOrder.for(BandwidthIris::Order.new(
+ order_status: "randOmgarBagE"
+ ))
+ assert_kind_of BandwidthTNOrder, order
+ assert_equal :randomgarbage, order.status
+ end
+
+ def test_poll
+ order = BandwidthTNOrder.new(BandwidthIris::Order.new)
+ assert_raises { order.poll.sync }
+ end
+ em :test_poll
+
+ class TestReceived < Minitest::Test
+ def setup
+ @order = BandwidthTNOrder::Received.new(
+ BandwidthIris::Order.new(id: "oid")
+ )
+ end
+
+ def test_poll
+ req = stub_request(
+ :get,
+ "https://dashboard.bandwidth.com/v1.0/accounts//orders/oid"
+ ).to_return(status: 200, body: <<~RESPONSE)
+ <OrderResponse>
+ <OrderStatus>COMPLETE</OrderStatus>
+ </OrderResponse>
+ RESPONSE
+ new_order = PromiseMock.new
+ new_order.expect(:poll, nil)
+ @order.poll.sync
+ assert_requested req
+ end
+ em :test_poll
+ end
+
+ class TestComplete < Minitest::Test
+ def setup
+ @order = BandwidthTNOrder::Complete.new(BandwidthIris::Order.new)
+ end
+
+ def test_poll
+ assert_equal @order, @order.poll.sync
+ end
+ em :test_poll
+ end
+
+ class TestFailed < Minitest::Test
+ def setup
+ @order = BandwidthTNOrder::Failed.new(
+ BandwidthIris::Order.new(id: "oid")
+ )
+ end
+
+ def test_poll
+ assert_raises { @order.poll.sync }
+ end
+ em :test_poll
+ end
+end
M test/test_helper.rb => test/test_helper.rb +17 -0
@@ 70,6 70,23 @@ class Matching
end
end
+class PromiseMock < Minitest::Mock
+ def then
+ yield self
+ end
+end
+
+module EventMachine
+ class << self
+ # Patch EM.add_timer to be instant in tests
+ alias old_add_timer add_timer
+ def add_timer(*args, &block)
+ args[0] = 0
+ old_add_timer(*args, &block)
+ end
+ end
+end
+
module Minitest
class Test
def self.property(m, &block)