Commit db6e3635 by andrew morton

Start resolving parameters

parent f37dda8c
...@@ -11,6 +11,7 @@ module RSpec ...@@ -11,6 +11,7 @@ module RSpec
config.extend Operation, swagger_object: :operation config.extend Operation, swagger_object: :operation
config.extend Parameters, swagger_object: :operation config.extend Parameters, swagger_object: :operation
config.extend Response, swagger_object: :status_code config.extend Response, swagger_object: :status_code
config.include Common, :swagger_object
end end
...@@ -42,6 +43,8 @@ paths: (Paths) ...@@ -42,6 +43,8 @@ paths: (Paths)
=end =end
module Paths module Paths
def path template, &block def path template, &block
raise ArgumentError, "Path must start with a /" unless template.starts_with?('/')
#TODO template might be a $ref #TODO template might be a $ref
meta = { meta = {
swagger_object: :path_item, swagger_object: :path_item,
...@@ -53,6 +56,8 @@ paths: (Paths) ...@@ -53,6 +56,8 @@ paths: (Paths)
module PathItem module PathItem
def operation verb, desc, &block def operation verb, desc, &block
# TODO, check verbs against a whitelist
verb = verb.to_s.downcase verb = verb.to_s.downcase
meta = { meta = {
swagger_object: :operation, swagger_object: :operation,
...@@ -72,12 +77,14 @@ paths: (Paths) ...@@ -72,12 +77,14 @@ paths: (Paths)
raise ArgumentError, "Invalid 'in' parameter, must be one of #{locations}" raise ArgumentError, "Invalid 'in' parameter, must be one of #{locations}"
end end
# Path attributes are always required
attributes[:required] = true if attributes[:in] == :path
# if name.respond_to?(:has_key?) # if name.respond_to?(:has_key?)
# param = { '$ref' => name.delete(:ref) || name.delete('ref') } # param = { '$ref' => name.delete(:ref) || name.delete('ref') }
# end # end
params_key = "#{metadata[:swagger_object]}_params".to_sym params = metadata[:swagger_data][:params] ||= {}
params = metadata[:swagger_data][params_key] ||= {}
param = { name: name.to_s }.merge(attributes) param = { name: name.to_s }.merge(attributes)
# Params should be unique based on the 'name' and 'in' values. # Params should be unique based on the 'name' and 'in' values.
...@@ -89,9 +96,8 @@ paths: (Paths) ...@@ -89,9 +96,8 @@ paths: (Paths)
module Operation module Operation
def response status_code, desc, params = {}, headers = {}, &block def response status_code, desc, params = {}, headers = {}, &block
unless status_code == :default || (100..599).cover?(status_code) unless status_code == :default || (100..599).cover?(status_code)
raise ArgumentError, "status_code must be between 100 and 599 or :default" raise ArgumentError, "status_code must be an integer 100 to 599, or :default"
end end
meta = { meta = {
swagger_object: :status_code, swagger_object: :status_code,
swagger_data: metadata[:swagger_data].merge(status_code: status_code, response_description: desc) swagger_data: metadata[:swagger_data].merge(status_code: status_code, response_description: desc)
...@@ -99,30 +105,29 @@ paths: (Paths) ...@@ -99,30 +105,29 @@ paths: (Paths)
describe("#{status_code}", meta) do describe("#{status_code}", meta) do
self.module_exec(&block) if block_given? self.module_exec(&block) if block_given?
method = metadata[:swagger_data][:operation] # TODO: this needs a better mechanism
path = metadata[:swagger_data][:path] if metadata[:capture_example]
example = metadata[:swagger_data][:example] = {}
end
before do |example|
method = example.metadata[:swagger_data][:operation]
path = resolve_path(example.metadata[:swagger_data][:path], self)
args = if ::Rails::VERSION::MAJOR >= 5 args = if ::Rails::VERSION::MAJOR >= 5
[path, {params: params, headers: headers}] [path, {params: params, headers: headers}]
else else
[path, params, headers] [path, params, headers]
end end
# TODO: this needs a better mechanism
if metadata[:capture_example]
example = metadata[:swagger_data][:example] = {}
end
meta = {
swagger_object: :response
# response: metadata[:swagger_data][:response].merge()
}
it("matches", meta) do
self.send(method, *args) self.send(method, *args)
if response && example # TODO fix the naming collision
example.merge!( body: response.body, content_type: response.content_type.to_s) # if example
# example.merge!(body: response.body, content_type: response.content_type.to_s)
# end
end end
it("matches", { swagger_object: :response }) do
expect(response).to have_http_status(status_code) expect(response).to have_http_status(status_code)
end end
end end
...@@ -134,6 +139,21 @@ paths: (Paths) ...@@ -134,6 +139,21 @@ paths: (Paths)
metadata[:capture_example] = true metadata[:capture_example] = true
end end
end end
module Common
def resolve_params swagger_data, group_instance
# TODO resolve $refs
# TODO there should only be one body param
# TODO there should not be both body and formData params
swagger_data[:params].values.map do |p|
p.slice(:name, :in).merge(value: group_instance.send(p[:name]))
end
end
def resolve_path template, group_instance
template.gsub(/(\{.*?\})/){|match| group_instance.send(match[1...-1]) }
end
end
end end
end end
end end
...@@ -15,8 +15,10 @@ RSpec.describe "Requestsing", type: :request do ...@@ -15,8 +15,10 @@ RSpec.describe "Requestsing", type: :request do
end end
end end
path '/posts/1' do path '/posts/{post_id}' do
parameter "path-param", {in: :path} parameter "post_id", {in: :path}
let(:post_id) { 1 }
operation "GET", "fetch item" do operation "GET", "fetch item" do
before { Post.new.save } before { Post.new.save }
parameter "op-param", {in: :query} parameter "op-param", {in: :query}
......
require "spec_helper" require "spec_helper"
RSpec.describe RSpec::Swagger::Helpers::Paths do
let(:klass) do
Class.new do
include RSpec::Swagger::Helpers::Paths
attr_accessor :metadata
def describe *args ; end
end
end
subject { klass.new }
it "requires the path start with a /" do
expect{ subject.path("foo") }.to raise_exception(ArgumentError)
expect{ subject.path("/foo") }.not_to raise_exception
end
end
RSpec.describe RSpec::Swagger::Helpers::Parameters do RSpec.describe RSpec::Swagger::Helpers::Parameters do
let(:klass) do let(:klass) do
Class.new do Class.new do
...@@ -13,39 +29,28 @@ RSpec.describe RSpec::Swagger::Helpers::Parameters do ...@@ -13,39 +29,28 @@ RSpec.describe RSpec::Swagger::Helpers::Parameters do
before { subject.metadata = {swagger_object: :path_item, swagger_data: {}} } before { subject.metadata = {swagger_object: :path_item, swagger_data: {}} }
it "requires 'in' parameter" do it "requires 'in' parameter" do
expect{ subject.parameter "name", foo: :bar }.to raise_exception(ArgumentError) expect{ subject.parameter("name", foo: :bar) }.to raise_exception(ArgumentError)
end end
it "validates 'in' parameter" do it "validates 'in' parameter" do
expect{ subject.parameter "name", in: :form_data }.to raise_exception(ArgumentError) expect{ subject.parameter("name", in: :form_data) }.to raise_exception(ArgumentError)
expect{ subject.parameter "name", in: "formData" }.to raise_exception(ArgumentError) expect{ subject.parameter("name", in: "formData") }.to raise_exception(ArgumentError)
expect{ subject.parameter "name", in: :formData }.not_to raise_exception expect{ subject.parameter("name", in: :formData) }.not_to raise_exception
end end
context "on a path_item" do it "marks path parameters as required" do
before { subject.metadata = {swagger_object: :path_item, swagger_data: {}} } subject.parameter("name", in: :path)
it "keeps parameters unique by name and in" do
subject.parameter('foo', in: :path)
subject.parameter('foo', in: :path)
subject.parameter('bar', in: :query)
subject.parameter('baz', in: :query)
expect(subject.metadata[:swagger_data][:path_item_params].length).to eq 3 expect(subject.metadata[:swagger_data][:params].values.first).to include(required: true)
end
end end
context "on an operation" do it "keeps parameters unique by name and location" do
before { subject.metadata = {swagger_object: :operation, swagger_data: {}} }
it "keeps parameters unique by name and in" do
subject.parameter('foo', in: :path) subject.parameter('foo', in: :path)
subject.parameter('foo', in: :path) subject.parameter('foo', in: :path)
subject.parameter('bar', in: :query) subject.parameter('bar', in: :query)
subject.parameter('baz', in: :query) subject.parameter('baz', in: :query)
expect(subject.metadata[:swagger_data][:operation_params].length).to eq 3 expect(subject.metadata[:swagger_data][:params].length).to eq 3
end
end end
end end
end end
...@@ -76,3 +81,54 @@ RSpec.describe RSpec::Swagger::Helpers::Operation do ...@@ -76,3 +81,54 @@ RSpec.describe RSpec::Swagger::Helpers::Operation do
end end
end end
end end
RSpec.describe RSpec::Swagger::Helpers::Common do
# Tthis helper is an include rather than an extend we can get it pulled into
# the test just by matching the filter metadata.
describe("#resolve_params", swagger_object: :something) do
let(:swagger_data) { { params: params } }
describe "with a missing value" do
let(:params) { {"path&post_id" => {name: "post_id", in: :path}} }
# TODO best thing would be to lazily evaulate the params so we'd only
# hit this if something was trying to use it.
it "raises an error" do
expect{resolve_params(swagger_data, self)}.to raise_exception(NoMethodError)
end
end
describe "with a valid value" do
let(:params) { {"path&post_id" => {name: "post_id", in: :path, description: "long"}} }
let(:post_id) { 123 }
it "returns it" do
expect(resolve_params(swagger_data, self)).to eq([{name: "post_id", in: :path, value: 123}])
end
end
end
describe("#resolve_params", swagger_object: :something) do
describe "with a missing value" do
it "raises an error" do
expect{ resolve_path('/sites/{site_id}', self) }.to raise_exception(NoMethodError)
end
end
describe "with values" do
let(:site_id) { 1001 }
let(:accountId) { "pickles" }
it "substitutes them into the path" do
expect(resolve_path('/sites/{site_id}/accounts/{accountId}', self)).to eq('/sites/1001/accounts/pickles')
end
end
describe "with a base path" do
xit "prefixes the path" do
end
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment