Skip to content

Commit

Permalink
add coercion modes for apiversion validation
Browse files Browse the repository at this point in the history
  • Loading branch information
jtgrenz committed Aug 12, 2019
1 parent 6b0544c commit a17c1f5
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 38 deletions.
2 changes: 0 additions & 2 deletions lib/shopify_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,3 @@ module ShopifyAPI
else
require 'active_resource/connection_ext'
end

ShopifyAPI::ApiVersion.define_known_versions
50 changes: 36 additions & 14 deletions lib/shopify_api/api_version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,63 @@ class InvalidVersion < StandardError; end
UNSTABLE_HANDLE = 'unstable'
UNSTABLE_AS_DATE = Time.utc(3000, 1, 1)
API_PREFIX = '/admin/api/'
COERSION_MODES = [:predefined_only, :define_on_unknown].freeze

class << self
attr_reader :versions

def coercion_mode
@coercion_mode ||= :define_on_unknown
end

def coercion_mode=(mode)
raise ArgumentError, "Mode must be one of #{COERSION_MODES}" unless COERSION_MODES.include?(mode)
sanitize_known_versions if mode == :predefined_only
@coercion_mode = mode
end

def coerce_to_version(version_or_handle)
return version_or_handle if version_or_handle.is_a?(ApiVersion)
if @versions.nil?
warn "[API VERSION WARNING] Known API Version set is empty. Initializing unvalidated version from handle."
return ApiVersion.new(handle: version_or_handle)
end

@versions[version_or_handle.to_s].tap do |api_version|
unless api_version
raise ApiVersion::UnknownVersion, "UnknownVersion API version specified, `#{version_or_handle}`. \n Versions available: #{@versions.keys}"
handle = version_or_handle.to_s

@versions ||= {}
@versions.fetch(handle) do
if @coercion_mode == :predefined_only
error_msg = if @versions.empty?
"No versions defined. You must call `ApiVersion.define_known_versions` first."
else
"`#{handle}` is not in the defined version set. Available versions: #{@versions.keys}"
end
raise UnknownVersion, "ApiVersion.coercion_mode is set to `:predefined_only`. #{error_msg}"
else
@versions[handle] = ApiVersion.new(handle: version_or_handle)
end
end
end

def define_known_versions
@versions = Meta.admin_versions.map { |version| [version.handle, version] }.to_h
rescue ActiveResource::ConnectionError => e
warn "[API VERSION WARNING] Could not fetch Admin API versions."
warn "[API VERSION WARNING] #{e.message}"
@versions = nil
end

def clear_defined_versions
@versions = nil
@versions = {}
end

def latest_stable_version
warn(
'[DEPRECATED] ShopifyAPI::ApiVersion.latest_stable_version is deprecated and will be removed in a future version.'
)
@versions.values.find(&:latest_supported?)
versions.values.find(&:latest_supported?)
end

private

def sanitize_known_versions
return if @versions.nil?
@versions = @versions.keys.map do |handle|
next unless @versions[handle].persisted?
[handle, @versions[handle]]
end.compact.to_h
end
end

Expand Down
34 changes: 25 additions & 9 deletions test/api_version_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,33 @@ class ApiVersionTest < Test::Unit::TestCase
])
end

test "coerce_to_version raises when coercing a string that doesn't match a known version" do
refute ShopifyAPI::ApiVersion.versions.nil?
assert_raises ShopifyAPI::ApiVersion::UnknownVersion do
test "coerce_to_version removes unpersisted versions from version set if mode is set to :predefined_only" do
ShopifyAPI::ApiVersion.coercion_mode = :define_on_unknown
assert ShopifyAPI::ApiVersion.versions.values.all?(&:persisted?)
assert_equal 5, ShopifyAPI::ApiVersion.versions.size

ShopifyAPI::ApiVersion.coerce_to_version('2019-30')
refute ShopifyAPI::ApiVersion.versions.values.all?(&:persisted?)
assert_equal 6, ShopifyAPI::ApiVersion.versions.size
ShopifyAPI::ApiVersion.coercion_mode = :predefined_only

assert ShopifyAPI::ApiVersion.versions.values.all?(&:persisted?)
assert_equal 5, ShopifyAPI::ApiVersion.versions.size
end

test "coerce_to_version does not raise when coercing a string if no versions are defined when coercion_mode is :define_on_unknown" do
ShopifyAPI::ApiVersion.clear_defined_versions
ShopifyAPI::ApiVersion.coercion_mode = :define_on_unknown
assert_equal :define_on_unknown, ShopifyAPI::ApiVersion.coercion_mode
assert_nothing_raised do
ShopifyAPI::ApiVersion.coerce_to_version('made up version')
end
end

test "coerce_to_version does not raise when coercing a string if no versions are defined" do
ShopifyAPI::ApiVersion.clear_defined_versions
assert_nil ShopifyAPI::ApiVersion.versions
assert_nothing_raised do
test "coerce_to_version does raise when coercing a string if no versions are defined when coercion_mode is :predefined_only" do
refute ShopifyAPI::ApiVersion.versions['made up version']
ShopifyAPI::ApiVersion.coercion_mode = :predefined_only
assert_raises ShopifyAPI::ApiVersion::UnknownVersion do
ShopifyAPI::ApiVersion.coerce_to_version('made up version')
end
end
Expand Down Expand Up @@ -77,8 +93,8 @@ class ApiVersionTest < Test::Unit::TestCase
"2019-01" => ShopifyAPI::ApiVersion.new(handle: '2019-01', supported: true, latest_supported: false),
"2019-04" => ShopifyAPI::ApiVersion.new(handle: '2019-04', supported: true, latest_supported: false),
"2019-07" => ShopifyAPI::ApiVersion.new(handle: '2019-07', supported: true, latest_supported: true),
"2019-10" => ShopifyAPI::ApiVersion.new(handle: '2019-10', supported: true, latest_supported: false),
"unstable" => ShopifyAPI::ApiVersion.new(handle: 'unstable', supported: true, latest_supported: false),
"2019-10" => ShopifyAPI::ApiVersion.new(handle: '2019-10', supported: false, latest_supported: false),
"unstable" => ShopifyAPI::ApiVersion.new(handle: 'unstable', supported: false, latest_supported: false),
}
)

Expand Down
17 changes: 12 additions & 5 deletions test/detailed_log_subscriber_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ def setup
@request_headers = "Headers: {\"Accept\"=>\"application/json\", " \
"#{@ua_header}, \"X-Shopify-Access-Token\"=>\"access_token\"}"

fake("api_versions",
ShopifyAPI::Base.clear_session
fake("apis",
url: "https://app.shopify.com/services/apis.json",
method: :get,
status: 200,
api_version: ShopifyAPI::ApiVersion.new(handle: :unstable),
body: load_fixture('api_versions'))

ShopifyAPI::Base.clear_session
api_version: :stub,
body: load_fixture('apis'))
ShopifyAPI::ApiVersion.define_known_versions
session = ShopifyAPI::Session.new(
domain: "https://this-is-my-test-shop.myshopify.com",
token: "access_token",
Expand All @@ -33,6 +34,12 @@ def setup
ActiveResource::DetailedLogSubscriber.attach_to :active_resource_detailed
end

def teardown
super
ShopifyAPI::ApiVersion.clear_defined_versions
ShopifyAPI::ApiVersion.coercion_mode = :predefined_only
end

def set_logger(logger)
ActiveResource::Base.logger = logger
end
Expand Down
9 changes: 1 addition & 8 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,6 @@
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))

FakeWeb.allow_net_connect = false
FakeWeb.register_uri(
:get,
"https://app.shopify.com/services/apis.json",
status: 200,
body: File.read(File.dirname(__FILE__) + "/fixtures/apis.json"),
content_type: "text/json"
)

require 'shopify_api'

Expand Down Expand Up @@ -72,8 +65,8 @@ def teardown
ShopifyAPI::Base.site = nil
ShopifyAPI::Base.password = nil
ShopifyAPI::Base.user = nil

ShopifyAPI::ApiVersion.clear_defined_versions
ShopifyAPI::ApiVersion.coercion_mode = :predefined_only
end

# Custom Assertions
Expand Down

0 comments on commit a17c1f5

Please sign in to comment.