mirror of
https://github.com/ditkrg/rswag.git
synced 2026-01-23 06:16:42 +00:00
rename & refactor example_builder
This commit is contained in:
parent
f9225a8a22
commit
071239727a
@ -1,85 +0,0 @@
|
|||||||
module SwaggerRails
|
|
||||||
|
|
||||||
class ExampleBuilder
|
|
||||||
attr_reader :expected_status
|
|
||||||
|
|
||||||
def initialize(path_template, http_method, swagger)
|
|
||||||
@path_template = path_template
|
|
||||||
@http_method = http_method
|
|
||||||
@swagger = swagger
|
|
||||||
@swagger_operation = find_swagger_operation!
|
|
||||||
@expected_status = find_swagger_success_status!
|
|
||||||
@param_values = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
def expect(status)
|
|
||||||
@expected_status = status
|
|
||||||
end
|
|
||||||
|
|
||||||
def set(param_values)
|
|
||||||
@param_values.merge!(param_values.stringify_keys)
|
|
||||||
end
|
|
||||||
|
|
||||||
def path
|
|
||||||
@path_template.dup.tap do |template|
|
|
||||||
template.prepend(@swagger['basePath'].presence || '')
|
|
||||||
path_params = param_values_for('path')
|
|
||||||
path_params.each { |name, value| template.sub!("\{#{name}\}", value) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def params
|
|
||||||
query_params = param_values_for('query')
|
|
||||||
body_params = param_values_for('body')
|
|
||||||
query_params.merge(body_params.values.first || {})
|
|
||||||
end
|
|
||||||
|
|
||||||
def headers
|
|
||||||
param_values_for('header')
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def find_swagger_operation!
|
|
||||||
find_swagger_item!('paths', @path_template, @http_method)
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_swagger_success_status!
|
|
||||||
path_keys = [ 'paths', @path_template, @http_method, 'responses' ]
|
|
||||||
responses = find_swagger_item!(*path_keys)
|
|
||||||
key = responses.keys.find { |k| k.start_with?('2') }
|
|
||||||
key ? key.to_i : (raise MetadataError.new(path_keys.concat('2xx')))
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_swagger_item!(*path_keys)
|
|
||||||
item = @swagger
|
|
||||||
path_keys.each do |key|
|
|
||||||
item = item[key] || (raise MetadataError.new(*path_keys))
|
|
||||||
end
|
|
||||||
item
|
|
||||||
end
|
|
||||||
|
|
||||||
def param_values_for(location)
|
|
||||||
params = (@swagger_operation['parameters'] || []).select { |p| p['in'] == location }
|
|
||||||
Hash[params.map { |param| [ param['name'], value_for(param) ] }]
|
|
||||||
end
|
|
||||||
|
|
||||||
def value_for(param)
|
|
||||||
return @param_values[param['name']] if @param_values.has_key?(param['name'])
|
|
||||||
return param['default'] unless param['in'] == 'body'
|
|
||||||
schema_for(param['schema'])['example']
|
|
||||||
end
|
|
||||||
|
|
||||||
def schema_for(schema_or_ref)
|
|
||||||
return schema_or_ref if schema_or_ref['$ref'].nil?
|
|
||||||
@swagger['definitions'][schema_or_ref['$ref'].sub('#/definitions/', '')]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class MetadataError < StandardError
|
|
||||||
def initialize(*path_keys)
|
|
||||||
path = path_keys.map { |key| "['#{key}']" }.join('')
|
|
||||||
super("Swagger document is missing expected metadata at #{path}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
92
lib/swagger_rails/testing/test_data_builder.rb
Normal file
92
lib/swagger_rails/testing/test_data_builder.rb
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
module SwaggerRails
|
||||||
|
|
||||||
|
class TestDataBuilder
|
||||||
|
|
||||||
|
def initialize(path_template, http_method, swagger)
|
||||||
|
@path_template = path_template
|
||||||
|
@http_method = http_method
|
||||||
|
@swagger = swagger
|
||||||
|
@param_values = {}
|
||||||
|
@expected_status = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def set(param_values)
|
||||||
|
@param_values.merge!(param_values.stringify_keys)
|
||||||
|
end
|
||||||
|
|
||||||
|
def expect(status)
|
||||||
|
@expected_status = status
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_data
|
||||||
|
operation = find_operation!
|
||||||
|
parameters = operation['parameters'] || []
|
||||||
|
responses = operation['responses']
|
||||||
|
{
|
||||||
|
path: build_path(parameters),
|
||||||
|
params: build_params(parameters),
|
||||||
|
headers: build_headers(parameters),
|
||||||
|
expected_response: build_expected_response(responses)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_operation!
|
||||||
|
keys = [ 'paths', @path_template, @http_method ]
|
||||||
|
operation = find_hash_item!(@swagger, keys)
|
||||||
|
operation || (raise MetadataError.new(keys))
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_hash_item!(hash, keys)
|
||||||
|
item = hash[keys[0]] || (return nil)
|
||||||
|
keys.length == 1 ? item : find_hash_item!(item, keys.drop(1))
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_path(parameters)
|
||||||
|
param_values = param_values_for(parameters, 'path')
|
||||||
|
@path_template.dup.tap do |template|
|
||||||
|
template.prepend(@swagger['basePath'].presence || '')
|
||||||
|
param_values.each { |name, value| template.sub!("\{#{name}\}", value) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_params(parameters)
|
||||||
|
{}.tap do |params|
|
||||||
|
params.merge!(param_values_for(parameters, 'query'))
|
||||||
|
body_param_values = param_values_for(parameters, 'body')
|
||||||
|
params.merge!(body_param_values.values.first) if body_param_values.any?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_headers(parameters)
|
||||||
|
param_values_for(parameters, 'header')
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_expected_response(responses)
|
||||||
|
end
|
||||||
|
|
||||||
|
def param_values_for(parameters, location)
|
||||||
|
applicable_parameters = parameters.select { |p| p['in'] == location }
|
||||||
|
Hash[applicable_parameters.map { |p| [ p['name'], value_for(p) ] }]
|
||||||
|
end
|
||||||
|
|
||||||
|
def value_for(param)
|
||||||
|
return @param_values[param['name']] if @param_values.has_key?(param['name'])
|
||||||
|
return param['default'] unless param['in'] == 'body'
|
||||||
|
schema_for(param['schema'])['example']
|
||||||
|
end
|
||||||
|
|
||||||
|
def schema_for(schema_or_ref)
|
||||||
|
return schema_or_ref if schema_or_ref['$ref'].nil?
|
||||||
|
@swagger['definitions'][schema_or_ref['$ref'].sub('#/definitions/', '')]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class MetadataError < StandardError
|
||||||
|
def initialize(*path_keys)
|
||||||
|
path = path_keys.map { |key| "['#{key}']" }.join('')
|
||||||
|
super("Swagger document is missing expected metadata at #{path}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -1,4 +1,4 @@
|
|||||||
require 'swagger_rails/testing/example_builder'
|
require 'swagger_rails/testing/test_data_builder'
|
||||||
|
|
||||||
module SwaggerRails
|
module SwaggerRails
|
||||||
|
|
||||||
@ -9,16 +9,17 @@ module SwaggerRails
|
|||||||
end
|
end
|
||||||
|
|
||||||
def run_test(path_template, http_method, test, &block)
|
def run_test(path_template, http_method, test, &block)
|
||||||
example = ExampleBuilder.new(path_template, http_method, @swagger)
|
builder = TestDataBuilder.new(path_template, http_method, @swagger)
|
||||||
example.instance_exec(&block) if block_given?
|
builder.instance_exec(&block) if block_given?
|
||||||
|
test_data = builder.test_data
|
||||||
|
|
||||||
test.send(http_method,
|
test.send(http_method,
|
||||||
example.path,
|
test_data[:path],
|
||||||
example.params,
|
test_data[:params],
|
||||||
example.headers
|
test_data[:headers]
|
||||||
)
|
)
|
||||||
|
|
||||||
test.assert_response(example.expected_status)
|
test.assert_response(test_data[:expected_status])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,119 +0,0 @@
|
|||||||
require 'rails_helper'
|
|
||||||
require 'swagger_rails/testing/example_builder'
|
|
||||||
|
|
||||||
module SwaggerRails
|
|
||||||
|
|
||||||
describe ExampleBuilder do
|
|
||||||
subject { described_class.new(path, method, swagger) }
|
|
||||||
let(:swagger) do
|
|
||||||
file_path = File.join(Rails.root, 'config/swagger', 'v1/swagger.json')
|
|
||||||
JSON.parse(File.read(file_path))
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#path' do
|
|
||||||
context 'operation with path params' do
|
|
||||||
let(:path) { '/blogs/{id}' }
|
|
||||||
let(:method) { 'get' }
|
|
||||||
|
|
||||||
context 'by default' do
|
|
||||||
it "returns path based on 'default' values" do
|
|
||||||
expect(subject.path).to eq('/blogs/123')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'values explicitly set' do
|
|
||||||
before { subject.set id: '456' }
|
|
||||||
it 'returns path based on set values' do
|
|
||||||
expect(subject.path).to eq('/blogs/456')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'swagger includes basePath' do
|
|
||||||
before { swagger['basePath'] = '/foobar' }
|
|
||||||
let(:path) { '/blogs' }
|
|
||||||
let(:method) { 'post' }
|
|
||||||
|
|
||||||
it 'returns path prefixed with basePath' do
|
|
||||||
expect(subject.path).to eq('/foobar/blogs')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#params' do
|
|
||||||
context 'operation with body param' do
|
|
||||||
let(:path) { '/blogs' }
|
|
||||||
let(:method) { 'post' }
|
|
||||||
|
|
||||||
context 'by default' do
|
|
||||||
it "returns schema 'example'" do
|
|
||||||
expect(subject.params).to eq(swagger['definitions']['Blog']['example'])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'value explicitly set' do
|
|
||||||
before { subject.set blog: { 'title' => 'foobar' } }
|
|
||||||
it 'returns params value' do
|
|
||||||
expect(subject.params).to eq({ 'title' => 'foobar' })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'operation with query params' do
|
|
||||||
let(:path) { '/blogs' }
|
|
||||||
let(:method) { 'get' }
|
|
||||||
|
|
||||||
context 'by default' do
|
|
||||||
it "returns query params based on 'default' values" do
|
|
||||||
expect(subject.params).to eq({ 'published' => 'true', 'keywords' => 'Ruby on Rails' })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'values explicitly set' do
|
|
||||||
before { subject.set keywords: 'Java' }
|
|
||||||
it 'returns query params based on set values' do
|
|
||||||
expect(subject.params).to eq({ 'published' => 'true', 'keywords' => 'Java' })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#headers' do
|
|
||||||
context 'operation with header params' do
|
|
||||||
let(:path) { '/blogs' }
|
|
||||||
let(:method) { 'post' }
|
|
||||||
|
|
||||||
context 'by default' do
|
|
||||||
it "returns headers based on 'default' values" do
|
|
||||||
expect(subject.headers).to eq({ 'X-Forwarded-For' => 'client1' })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'values explicitly params' do
|
|
||||||
before { subject.set 'X-Forwarded-For' => '192.168.1.1' }
|
|
||||||
it 'returns headers based on params values' do
|
|
||||||
expect(subject.headers).to eq({ 'X-Forwarded-For' => '192.168.1.1' })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#expected_status' do
|
|
||||||
let(:path) { '/blogs' }
|
|
||||||
let(:method) { 'post' }
|
|
||||||
|
|
||||||
context 'by default' do
|
|
||||||
it "returns first 2xx status in 'responses'" do
|
|
||||||
expect(subject.expected_status).to eq(200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'expected status explicitly params' do
|
|
||||||
before { subject.expect 400 }
|
|
||||||
it "returns params status" do
|
|
||||||
expect(subject.expected_status).to eq(400)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
99
spec/testing/test_data_builder_spec.rb
Normal file
99
spec/testing/test_data_builder_spec.rb
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
require 'swagger_rails/testing/test_data_builder'
|
||||||
|
|
||||||
|
module SwaggerRails
|
||||||
|
|
||||||
|
describe TestDataBuilder do
|
||||||
|
subject { described_class.new(path, method, swagger) }
|
||||||
|
let(:swagger) do
|
||||||
|
file_path = File.join(Rails.root, 'config/swagger', 'v1/swagger.json')
|
||||||
|
JSON.parse(File.read(file_path))
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#test_data' do
|
||||||
|
let(:test_data) { subject.test_data }
|
||||||
|
|
||||||
|
context 'swagger includes basePath' do
|
||||||
|
before { swagger['basePath'] = '/foobar' }
|
||||||
|
let(:path) { '/blogs' }
|
||||||
|
let(:method) { 'post' }
|
||||||
|
|
||||||
|
it 'includes a path prefixed with basePath' do
|
||||||
|
expect(test_data[:path]).to eq('/foobar/blogs')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'operation has path params' do
|
||||||
|
let(:path) { '/blogs/{id}' }
|
||||||
|
let(:method) { 'get' }
|
||||||
|
|
||||||
|
context 'by default' do
|
||||||
|
it "includes a path built from 'default' values" do
|
||||||
|
expect(test_data[:path]).to eq('/blogs/123')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'values explicitly set' do
|
||||||
|
before { subject.set id: '456' }
|
||||||
|
it 'includes a path built from set values' do
|
||||||
|
expect(test_data[:path]).to eq('/blogs/456')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'operation has query params' do
|
||||||
|
let(:path) { '/blogs' }
|
||||||
|
let(:method) { 'get' }
|
||||||
|
|
||||||
|
context 'by default' do
|
||||||
|
it "includes params built from 'default' values" do
|
||||||
|
expect(test_data[:params]).to eq({ 'published' => 'true', 'keywords' => 'Ruby on Rails' })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'values explicitly set' do
|
||||||
|
before { subject.set keywords: 'Java' }
|
||||||
|
it 'includes params build from set values' do
|
||||||
|
expect(test_data[:params]).to eq({ 'published' => 'true', 'keywords' => 'Java' })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'operation has body params' do
|
||||||
|
let(:path) { '/blogs' }
|
||||||
|
let(:method) { 'post' }
|
||||||
|
|
||||||
|
context 'by default' do
|
||||||
|
it "includes params built from 'default' values" do
|
||||||
|
expect(test_data[:params]).to eq({ 'title' => 'Test Blog', 'content' => 'Hello World' })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'values explicitly set' do
|
||||||
|
before { subject.set blog: { 'title' => 'foobar' } }
|
||||||
|
it 'includes params build from set values' do
|
||||||
|
expect(test_data[:params]).to eq({ 'title' => 'foobar' })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'operation has header params' do
|
||||||
|
let(:path) { '/blogs' }
|
||||||
|
let(:method) { 'post' }
|
||||||
|
|
||||||
|
context 'by default' do
|
||||||
|
it "includes headers built from 'default' values" do
|
||||||
|
expect(test_data[:headers]).to eq({ 'X-Forwarded-For' => 'client1' })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'values explicitly params' do
|
||||||
|
before { subject.set 'X-Forwarded-For' => '192.168.1.1' }
|
||||||
|
it 'includes headers built from set values' do
|
||||||
|
expect(test_data[:headers]).to eq({ 'X-Forwarded-For' => '192.168.1.1' })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user