mirror of
https://github.com/stripe/stripe-ruby.git
synced 2025-10-09 00:03:05 -04:00
I'd originally added this class for the first stub pass that used OpenAPI because I thought we'd need the ability to finetune some of our stubbed responses. It turns out that we've been able to get away without it so far so I'm removing it for now. This commit can be reverted if it turns out that we need it back later.
126 lines
4.3 KiB
Ruby
126 lines
4.3 KiB
Ruby
require "json"
|
|
|
|
# Provides a set of helpers for a test suite that help to mock out the Stripe
|
|
# API.
|
|
module APIStubHelpers
|
|
protected
|
|
|
|
# Uses Webmock to stub out the Stripe API for testing purposes. The stub will
|
|
# by default respond on any routes that are defined in the bundled OpenAPI
|
|
# spec with generated response data.
|
|
#
|
|
# An `override_app` can be specified to get finer grain control over how a
|
|
# stubbed endpoint responds. It can be used to modify generated responses,
|
|
# mock expectations, or even to override the default stub completely.
|
|
def stub_api
|
|
stub_request(:any, /^#{Stripe.api_base}/).to_rack(new_api_stub)
|
|
end
|
|
|
|
def stub_connect
|
|
stub_request(:any, /^#{Stripe.connect_base}/).to_return(:body => "{}")
|
|
end
|
|
|
|
private
|
|
|
|
# APIStubMiddleware intercepts a response generated by Committee's stubbing
|
|
# middleware, and tries to replace it with a better version from a set of
|
|
# sample fixtures data generated from Stripe's core API service.
|
|
class APIStubMiddleware
|
|
API_FIXTURES = APIFixtures.new
|
|
|
|
def initialize(app)
|
|
@app = app
|
|
end
|
|
|
|
def call(env)
|
|
# We use a vendor specific prefix (`x-resourceId`) embedded in the schema
|
|
# of any resource in our spec to identify it (e.g. "charge"). This allows
|
|
# us to cross-reference that response with some data that we might find
|
|
# in our fixtures file so that we can respond with a higher fidelity
|
|
# response.
|
|
schema = env["committee.response_schema"]
|
|
resource_id = schema.data["x-resourceId"] || ""
|
|
|
|
if data = API_FIXTURES[resource_id.to_sym]
|
|
# standard top-level API resource
|
|
data = fixturize_lists_recursively(schema, data)
|
|
env["committee.response"] = data
|
|
elsif schema.properties["object"].enum == ["list"]
|
|
# top level list (like from a list endpoint)
|
|
data = fixturize_list(schema, env["committee.response"])
|
|
env["committee.response"] = data
|
|
else
|
|
raise "no fixture for: #{resource_id}"
|
|
end
|
|
@app.call(env)
|
|
end
|
|
|
|
private
|
|
|
|
# If schema looks like a Stripe list object, then we look up the resource
|
|
# that the list is supposed to include and inject it into `data` as a
|
|
# fixture. Also calls into that other schema recursively so that sublists
|
|
# within it will also be assigned a fixture.
|
|
def fixturize_list(schema, data)
|
|
object_schema = schema.properties["object"]
|
|
if object_schema && object_schema.enum == ["list"]
|
|
subschema = schema.properties["data"].items
|
|
resource_id = subschema.data["x-resourceId"] || ""
|
|
if subdata = API_FIXTURES[resource_id.to_sym]
|
|
subdata = fixturize_lists_recursively(subschema, subdata)
|
|
|
|
data = data ? data.dup : {}
|
|
data[:data] = [subdata]
|
|
end
|
|
end
|
|
data
|
|
end
|
|
|
|
# Examines each of the given schema's properties and calls #fixturize_list
|
|
# on them so that any sublists will be populated with sample fixture data.
|
|
def fixturize_lists_recursively(schema, data)
|
|
data = data.dup
|
|
schema.properties.each do |key, subschema|
|
|
data[key.to_sym] = fixturize_list(subschema, data[key.to_sym])
|
|
end
|
|
data
|
|
end
|
|
end
|
|
|
|
# A descendant of the standard `Sinatra::Base` that we can use to enrich
|
|
# certain types of responses.
|
|
class APIStubApp < Sinatra::Base
|
|
not_found do
|
|
"endpoint not found in API stub: #{request.request_method} #{request.path_info}"
|
|
end
|
|
end
|
|
|
|
# Finds the latest OpenAPI specification in ROOT/spec/ and parses it for
|
|
# use with Committee.
|
|
def self.initialize_spec
|
|
schema_data = ::JSON.parse(File.read("#{PROJECT_ROOT}/spec/spec.json"))
|
|
|
|
driver = Committee::Drivers::OpenAPI2.new
|
|
driver.parse(schema_data)
|
|
end
|
|
|
|
# Creates a new Rack app with Committee middleware it.
|
|
def new_api_stub
|
|
Rack::Builder.new {
|
|
use Committee::Middleware::RequestValidation, schema: @@spec,
|
|
params_response: true, strict: true
|
|
use Committee::Middleware::Stub, schema: @@spec,
|
|
call: true
|
|
use APIStubMiddleware
|
|
run APIStubApp.new
|
|
}
|
|
end
|
|
|
|
# Parse and initialize the OpenAPI spec only once for the entire test suite.
|
|
@@spec = initialize_spec
|
|
|
|
# The default override app. Doesn't respond on any route so generated
|
|
# responses will always take precedence.
|
|
@@default_override_app = Sinatra.new
|
|
end
|