apipie-rails 1.1.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/build.yml +12 -48
- data/.github/workflows/rubocop-challenger.yml +2 -2
- data/.github/workflows/rubocop.yml +2 -4
- data/.rubocop.yml +39 -38
- data/.rubocop_todo.yml +55 -65
- data/.vscode/settings.json +3 -0
- data/CHANGELOG.md +19 -2
- data/Gemfile +20 -0
- data/README.rst +12 -9
- data/app/controllers/apipie/apipies_controller.rb +3 -17
- data/gemfiles/Gemfile.tools +9 -0
- data/lib/apipie/application.rb +18 -7
- data/lib/apipie/dsl_definition.rb +6 -5
- data/lib/apipie/errors.rb +14 -0
- data/lib/apipie/extractor/collector.rb +1 -1
- data/lib/apipie/extractor/recorder.rb +1 -1
- data/lib/apipie/extractor.rb +6 -3
- data/lib/apipie/generator/swagger/config.rb +3 -1
- data/lib/apipie/generator/swagger/method_description/api_schema_service.rb +6 -3
- data/lib/apipie/generator/swagger/warning.rb +1 -1
- data/lib/apipie/resource_description.rb +28 -3
- data/lib/apipie/validator.rb +20 -6
- data/lib/apipie/version.rb +1 -1
- data/spec/controllers/api/v2/architectures_controller_spec.rb +10 -3
- data/spec/controllers/api/v2/empty_middle_controller_spec.rb +23 -0
- data/spec/controllers/api/v2/nested/resources_controller_spec.rb +16 -0
- data/spec/controllers/api/v2/sub/footguns_controller_spec.rb +19 -0
- data/spec/controllers/users_controller_spec.rb +10 -0
- data/spec/dummy/app/controllers/api/v2/base_controller.rb +6 -0
- data/spec/dummy/app/controllers/api/v2/empty_middle_controller.rb +14 -0
- data/spec/dummy/app/controllers/api/v2/nested/resources_controller.rb +2 -2
- data/spec/dummy/app/controllers/api/v2/sub/footguns_controller.rb +30 -0
- data/spec/dummy/app/controllers/users_controller.rb +6 -0
- data/spec/dummy/config/routes.rb +1 -0
- data/spec/lib/apipie/apipies_controller_spec.rb +63 -19
- data/spec/lib/apipie/extractor/collector_spec.rb +57 -0
- data/spec/lib/apipie/generator/swagger/method_description/api_schema_service_spec.rb +13 -0
- data/spec/test_engine/memes_controller_spec.rb +1 -1
- metadata +11 -9
- data/gemfiles/Gemfile.rails50 +0 -10
- data/gemfiles/Gemfile.rails51 +0 -10
- data/gemfiles/Gemfile.rails52 +0 -10
- data/gemfiles/Gemfile.rails60 +0 -17
- data/gemfiles/Gemfile.rails61 +0 -17
- data/gemfiles/Gemfile.rails70 +0 -17
@@ -241,9 +241,11 @@ module Apipie
|
|
241
241
|
method_params = self.class._apipie_get_method_params(action_name)
|
242
242
|
|
243
243
|
if Apipie.configuration.validate_presence?
|
244
|
-
|
245
|
-
|
246
|
-
|
244
|
+
Validator::BaseValidator.raise_if_missing_params do |missing|
|
245
|
+
method_params.each do |_, param|
|
246
|
+
# check if required parameters are present
|
247
|
+
missing << param if param.required && !params.key?(param.name)
|
248
|
+
end
|
247
249
|
end
|
248
250
|
end
|
249
251
|
|
@@ -259,7 +261,7 @@ module Apipie
|
|
259
261
|
if Apipie.configuration.validate_key?
|
260
262
|
params.reject{|k,_| %w[format controller action].include?(k.to_s) }.each_pair do |param, _|
|
261
263
|
# params allowed
|
262
|
-
if method_params.
|
264
|
+
if method_params.none? {|_,p| p.name.to_s == param.to_s}
|
263
265
|
self.class._apipie_handle_validate_key_error params, param
|
264
266
|
end
|
265
267
|
end
|
@@ -285,7 +287,6 @@ module Apipie
|
|
285
287
|
old_method.bind(self).call(*args)
|
286
288
|
end
|
287
289
|
end
|
288
|
-
|
289
290
|
end
|
290
291
|
end
|
291
292
|
|
data/lib/apipie/errors.rb
CHANGED
@@ -24,6 +24,20 @@ module Apipie
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
class ParamMultipleMissing < ParamError
|
28
|
+
attr_accessor :params
|
29
|
+
|
30
|
+
def initialize(params)
|
31
|
+
@params = params
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
params.map do |param|
|
36
|
+
ParamMissing.new(param).to_s
|
37
|
+
end.join("\n")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
27
41
|
class ParamMissing < DefinedParamError
|
28
42
|
def to_s
|
29
43
|
unless @param.options[:missing_message].nil?
|
@@ -19,7 +19,7 @@ module Apipie
|
|
19
19
|
def ignore_call?(record)
|
20
20
|
return true unless record[:controller]
|
21
21
|
return true if @ignored.include?(record[:controller].name)
|
22
|
-
return true if @ignored.include?("#{Apipie.
|
22
|
+
return true if @ignored.include?("#{Apipie.get_resource_id(record[:controller].name)}##{record[:action]}")
|
23
23
|
return true unless @api_controllers_paths.include?(controller_full_path(record[:controller]))
|
24
24
|
end
|
25
25
|
|
data/lib/apipie/extractor.rb
CHANGED
@@ -15,10 +15,13 @@ class Apipie::Railtie
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
18
|
-
app.middleware.use ::Apipie::Extractor::Recorder::Middleware
|
19
18
|
|
20
|
-
|
21
|
-
|
19
|
+
if Apipie.configuration.record
|
20
|
+
app.middleware.use ::Apipie::Extractor::Recorder::Middleware
|
21
|
+
|
22
|
+
ActionController::TestCase.send(:prepend, Apipie::Extractor::Recorder::FunctionalTestRecording)
|
23
|
+
ActionController::TestCase::Behavior.send(:prepend, Apipie::Extractor::Recorder::FunctionalTestRecording)
|
24
|
+
end
|
22
25
|
end
|
23
26
|
end
|
24
27
|
|
@@ -10,7 +10,7 @@ module Apipie
|
|
10
10
|
:json_input_uses_refs, :suppress_warnings, :api_host,
|
11
11
|
:generate_x_computed_id_field, :allow_additional_properties_in_response,
|
12
12
|
:responses_use_refs, :schemes, :security_definitions,
|
13
|
-
:global_security].freeze
|
13
|
+
:global_security, :skip_default_tags].freeze
|
14
14
|
|
15
15
|
attr_accessor(*CONFIG_ATTRIBUTES)
|
16
16
|
|
@@ -43,6 +43,7 @@ module Apipie
|
|
43
43
|
alias include_warning_tags? include_warning_tags
|
44
44
|
alias json_input_uses_refs? json_input_uses_refs
|
45
45
|
alias responses_use_refs? responses_use_refs
|
46
|
+
alias skip_default_tags? skip_default_tags
|
46
47
|
alias generate_x_computed_id_field? generate_x_computed_id_field
|
47
48
|
alias swagger_include_warning_tags? swagger_include_warning_tags
|
48
49
|
alias swagger_json_input_uses_refs? swagger_json_input_uses_refs
|
@@ -61,6 +62,7 @@ module Apipie
|
|
61
62
|
@schemes = [:https]
|
62
63
|
@security_definitions = {}
|
63
64
|
@global_security = []
|
65
|
+
@skip_default_tags = false
|
64
66
|
end
|
65
67
|
|
66
68
|
def self.deprecated_methods
|
@@ -47,9 +47,12 @@ class Apipie::Generator::Swagger::MethodDescription::ApiSchemaService
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def tags
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
tags = if Apipie.configuration.generator.swagger.skip_default_tags?
|
51
|
+
[]
|
52
|
+
else
|
53
|
+
[@method_description.resource._id]
|
54
|
+
end
|
55
|
+
tags + warning_tags + @method_description.tag_list.tags
|
53
56
|
end
|
54
57
|
|
55
58
|
def warning_tags
|
@@ -59,7 +59,7 @@ class Apipie::Generator::Swagger::Warning
|
|
59
59
|
#
|
60
60
|
# @return [Apipie::Generator::Swagger::Warning]
|
61
61
|
def self.for_code(code, method_id, message_attributes = {})
|
62
|
-
if !CODES.
|
62
|
+
if !CODES.value?(code)
|
63
63
|
raise ArgumentError, 'Unknown warning code'
|
64
64
|
end
|
65
65
|
|
@@ -26,7 +26,9 @@ module Apipie
|
|
26
26
|
@controller = controller
|
27
27
|
@_id = id
|
28
28
|
@_version = version || Apipie.configuration.default_version
|
29
|
-
@_parent = Apipie.
|
29
|
+
@_parent = Apipie.value_from_parents(controller.superclass, version) do |parent, ver|
|
30
|
+
Apipie.get_resource_description(parent, ver)
|
31
|
+
end
|
30
32
|
|
31
33
|
update_from_dsl_data(dsl_data) if dsl_data
|
32
34
|
end
|
@@ -60,7 +62,16 @@ module Apipie
|
|
60
62
|
end
|
61
63
|
|
62
64
|
def name
|
63
|
-
@name ||=
|
65
|
+
@name ||= case resource_name
|
66
|
+
when Proc
|
67
|
+
resource_name.call(controller)
|
68
|
+
when Symbol
|
69
|
+
controller.public_send(resource_name)
|
70
|
+
when String
|
71
|
+
resource_name
|
72
|
+
else
|
73
|
+
default_name
|
74
|
+
end
|
64
75
|
end
|
65
76
|
alias _name name
|
66
77
|
|
@@ -90,7 +101,9 @@ module Apipie
|
|
90
101
|
Apipie.full_url crumbs.join('/')
|
91
102
|
end
|
92
103
|
|
93
|
-
def api_url
|
104
|
+
def api_url
|
105
|
+
"#{Apipie.api_base_url(_version)}#{@_path}"
|
106
|
+
end
|
94
107
|
|
95
108
|
def valid_method_name?(method_name)
|
96
109
|
@_methods.keys.map(&:to_s).include?(method_name.to_s)
|
@@ -123,5 +136,17 @@ module Apipie
|
|
123
136
|
}
|
124
137
|
end
|
125
138
|
|
139
|
+
protected
|
140
|
+
|
141
|
+
def resource_name
|
142
|
+
@_resource_name.presence || @_parent&.resource_name
|
143
|
+
end
|
144
|
+
|
145
|
+
private
|
146
|
+
|
147
|
+
def default_name
|
148
|
+
@_id.split('-').map(&:capitalize).join('::')
|
149
|
+
end
|
150
|
+
|
126
151
|
end
|
127
152
|
end
|
data/lib/apipie/validator.rb
CHANGED
@@ -38,6 +38,16 @@ module Apipie
|
|
38
38
|
return nil
|
39
39
|
end
|
40
40
|
|
41
|
+
def self.raise_if_missing_params
|
42
|
+
missing_params = []
|
43
|
+
yield missing_params
|
44
|
+
if missing_params.size > 1
|
45
|
+
raise ParamMultipleMissing.new(missing_params)
|
46
|
+
elsif missing_params.size == 1
|
47
|
+
raise ParamMissing.new(missing_params.first)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
41
51
|
# check if value is valid
|
42
52
|
def valid?(value)
|
43
53
|
if self.validate(value)
|
@@ -345,14 +355,18 @@ module Apipie
|
|
345
355
|
|
346
356
|
def validate(value)
|
347
357
|
return false if !value.is_a? Hash
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
358
|
+
|
359
|
+
BaseValidator.raise_if_missing_params do |missing|
|
360
|
+
@hash_params&.each do |k, p|
|
361
|
+
if Apipie.configuration.validate_presence?
|
362
|
+
missing << p if p.required && !value.key?(k)
|
363
|
+
end
|
364
|
+
if Apipie.configuration.validate_value?
|
365
|
+
p.validate(value[k]) if value.key?(k)
|
366
|
+
end
|
354
367
|
end
|
355
368
|
end
|
369
|
+
|
356
370
|
return true
|
357
371
|
end
|
358
372
|
|
data/lib/apipie/version.rb
CHANGED
@@ -1,12 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Api::V2::ArchitecturesController do
|
4
|
+
let(:resource_description) { Apipie.get_resource_description(described_class, "2.0") }
|
5
|
+
|
4
6
|
describe "resource description" do
|
5
|
-
|
7
|
+
describe 'version' do
|
8
|
+
subject { resource_description._version }
|
6
9
|
|
7
|
-
|
8
|
-
expect(subject._version).to eq('2.0')
|
10
|
+
it { is_expected.to eq('2.0') }
|
9
11
|
end
|
10
12
|
|
13
|
+
describe 'name' do
|
14
|
+
subject { resource_description.name }
|
15
|
+
|
16
|
+
it { is_expected.to eq('Architectures') }
|
17
|
+
end
|
11
18
|
end
|
12
19
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Api::V2::EmptyMiddleController do
|
4
|
+
let(:resource_description) { Apipie.get_resource_description(described_class, '2.0') }
|
5
|
+
|
6
|
+
describe 'resource description' do
|
7
|
+
subject { resource_description }
|
8
|
+
|
9
|
+
context 'when namespaced resources are enabled' do
|
10
|
+
before { Apipie.configuration.namespaced_resources = true }
|
11
|
+
after { Apipie.configuration.namespaced_resources = false }
|
12
|
+
|
13
|
+
# we don't actually expect the resource description to be nil, but resource IDs
|
14
|
+
# are computed at file load time, and altering the value of namespaced_resources
|
15
|
+
# after the fact doesn't change the resource ID, so it can't be found
|
16
|
+
it { is_expected.to be_nil }
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when namespaced resources are disabled' do
|
20
|
+
it { is_expected.to be_nil }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,6 +1,22 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Api::V2::Nested::ResourcesController do
|
4
|
+
let(:resource_description) { Apipie.get_resource_description(described_class, "2.0") }
|
5
|
+
|
6
|
+
describe "resource description" do
|
7
|
+
describe 'version' do
|
8
|
+
subject { resource_description._version }
|
9
|
+
|
10
|
+
it { is_expected.to eq('2.0') }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'name' do
|
14
|
+
subject { resource_description.name }
|
15
|
+
|
16
|
+
it { is_expected.to eq('Rsrcs') }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
4
20
|
describe '.get_resource_id' do
|
5
21
|
subject { Apipie.get_resource_id(Api::V2::Nested::ResourcesController) }
|
6
22
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Api::V2::Sub::FootgunsController do
|
4
|
+
let(:resource_description) { Apipie.get_resource_description(described_class, '2.0') }
|
5
|
+
|
6
|
+
describe 'resource description' do
|
7
|
+
describe 'version' do
|
8
|
+
subject { resource_description._version }
|
9
|
+
|
10
|
+
it { is_expected.to eq('2.0') }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'name' do
|
14
|
+
subject { resource_description.name }
|
15
|
+
|
16
|
+
it { is_expected.to eq('snugtooF') }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -37,6 +37,7 @@ describe UsersController do
|
|
37
37
|
expect(methods.keys).to include(:update)
|
38
38
|
expect(methods.keys).to include(:two_urls)
|
39
39
|
expect(methods.keys).to include(:action_with_headers)
|
40
|
+
expect(methods.keys).to include(:multiple_required_params)
|
40
41
|
end
|
41
42
|
|
42
43
|
it "should contain info about resource" do
|
@@ -101,6 +102,10 @@ describe UsersController do
|
|
101
102
|
expect { get :show, :params => { :id => 5 }}.to raise_error(Apipie::ParamMissing, /session_parameter_is_required/)
|
102
103
|
end
|
103
104
|
|
105
|
+
it "should fail if multiple required parameters are missing" do
|
106
|
+
expect { get :multiple_required_params }.to raise_error(Apipie::ParamMultipleMissing, /required_param1.*\n.*required_param2|required_param2.*\n.*required_parameter1/)
|
107
|
+
end
|
108
|
+
|
104
109
|
it "should pass if required parameter has wrong type" do
|
105
110
|
expect { get :show, :params => { :id => 5 , :session => "secret_hash" }}.not_to raise_error
|
106
111
|
expect { get :show, :params => { :id => "ten" , :session => "secret_hash" }}.not_to raise_error
|
@@ -246,6 +251,11 @@ describe UsersController do
|
|
246
251
|
post :create, :params => { :user => { :name => "root", :pass => "12345", :membership => "____" } }
|
247
252
|
}.to raise_error(Apipie::ParamInvalid, /membership/)
|
248
253
|
|
254
|
+
# Should include both pass and name
|
255
|
+
expect {
|
256
|
+
post :create, :params => { :user => { :membership => "standard" } }
|
257
|
+
}.to raise_error(Apipie::ParamMultipleMissing, /pass.*\n.*name|name.*\n.*pass/)
|
258
|
+
|
249
259
|
expect {
|
250
260
|
post :create, :params => { :user => { :name => "root" } }
|
251
261
|
}.to raise_error(Apipie::ParamMissing, /pass/)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Api
|
2
|
+
module V2
|
3
|
+
class EmptyMiddleController < V2::BaseController
|
4
|
+
# This is an empty controller, used to test cases where controllers
|
5
|
+
# may inherit from a middle controler that does not define a resource_description,
|
6
|
+
# but the middle controller's parent does.
|
7
|
+
|
8
|
+
def inconsequential_method
|
9
|
+
# This method is here to ensure that the controller is not empty.
|
10
|
+
# It triggers method_added, which is used to add the resource description.
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Api
|
2
2
|
module V2
|
3
3
|
class Nested::ResourcesController < V2::BaseController
|
4
|
-
resource_description do
|
5
|
-
name '
|
4
|
+
resource_description do
|
5
|
+
name ->(controller) { controller.controller_name.delete('aeiou').capitalize }
|
6
6
|
resource_id "resource"
|
7
7
|
end
|
8
8
|
api :GET, "/nested/resources/", "List all nested resources."
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Api
|
2
|
+
module V2
|
3
|
+
module Sub
|
4
|
+
class FootgunsController < V2::EmptyMiddleController
|
5
|
+
resource_description do
|
6
|
+
short 'Footguns are bad'
|
7
|
+
end
|
8
|
+
|
9
|
+
api :GET, '/footguns/', 'List all footguns.'
|
10
|
+
def index; end
|
11
|
+
|
12
|
+
api :GET, '/footguns/:id/', 'Show a footgun.'
|
13
|
+
def show; end
|
14
|
+
|
15
|
+
api :POST, '/footguns/', 'Create a footgun.'
|
16
|
+
def create; end
|
17
|
+
|
18
|
+
api :PUT, '/footguns/:id/', 'Update a footgun.'
|
19
|
+
param :footgun, Hash, :required => true do
|
20
|
+
param :name, String
|
21
|
+
end
|
22
|
+
def update; end
|
23
|
+
|
24
|
+
api! 'Delete a footgun.'
|
25
|
+
api_version '2.0' # forces removal of the method description
|
26
|
+
def destroy; end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -301,4 +301,10 @@ class UsersController < ApplicationController
|
|
301
301
|
header :HeaderNameWithDefaultValue, 'Header with default value', required: true, default: 'default value'
|
302
302
|
def action_with_headers
|
303
303
|
end
|
304
|
+
|
305
|
+
api :GET, '/users/multiple_required_params'
|
306
|
+
param :required_param1, String, required: true
|
307
|
+
param :required_param2, String, required: true
|
308
|
+
def multiple_required_params
|
309
|
+
end
|
304
310
|
end
|
data/spec/dummy/config/routes.rb
CHANGED
@@ -258,12 +258,12 @@ describe Apipie::ApipiesController, type: :controller do
|
|
258
258
|
|
259
259
|
before do
|
260
260
|
FileUtils.rm_r(cache_dir) if File.exist?(cache_dir)
|
261
|
-
FileUtils.mkdir_p(File.join(cache_dir, "apidoc", "v1", "resource"))
|
261
|
+
FileUtils.mkdir_p(File.join(cache_dir, "apidoc", "v1", "resource-with-namespace"))
|
262
262
|
File.open(File.join(cache_dir, "apidoc", "v1.html"), "w") { |f| f << "apidoc.html cache v1" }
|
263
263
|
File.open(File.join(cache_dir, "apidoc", "v2.html"), "w") { |f| f << "apidoc.html cache v2" }
|
264
264
|
File.open(File.join(cache_dir, "apidoc", "v1.json"), "w") { |f| f << "apidoc.json cache" }
|
265
|
-
File.open(File.join(cache_dir, "apidoc", "v1", "resource.html"), "w") { |f| f << "resource.html cache" }
|
266
|
-
File.open(File.join(cache_dir, "apidoc", "v1", "resource", "method.html"), "w") { |f| f << "method.html cache" }
|
265
|
+
File.open(File.join(cache_dir, "apidoc", "v1", "resource-with-namespace.html"), "w") { |f| f << "resource-with-namespace.html cache" }
|
266
|
+
File.open(File.join(cache_dir, "apidoc", "v1", "resource-with-namespace", "method.html"), "w") { |f| f << "method.html cache" }
|
267
267
|
|
268
268
|
Apipie.configuration.use_cache = true
|
269
269
|
@orig_cache_dir = Apipie.configuration.cache_dir
|
@@ -279,24 +279,68 @@ describe Apipie::ApipiesController, type: :controller do
|
|
279
279
|
# FileUtils.rm_r(cache_dir) if File.exist?(cache_dir)
|
280
280
|
end
|
281
281
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
282
|
+
context 'when the file exists' do
|
283
|
+
it "uses the file in cache dir instead of generating the content on runtime" do
|
284
|
+
get :index
|
285
|
+
expect(response.body).to eq("apidoc.html cache v1")
|
286
|
+
|
287
|
+
get :index, :params => { :version => 'v1' }
|
288
|
+
expect(response.body).to eq("apidoc.html cache v1")
|
289
|
+
|
290
|
+
get :index, :params => { :version => 'v2' }
|
291
|
+
expect(response.body).to eq("apidoc.html cache v2")
|
292
|
+
|
293
|
+
get :index, :params => { :version => 'v1', :format => "html" }
|
294
|
+
expect(response.body).to eq("apidoc.html cache v1")
|
295
|
+
|
296
|
+
get :index, :params => { :version => 'v1', :format => "json" }
|
297
|
+
expect(response.body).to eq("apidoc.json cache")
|
298
|
+
|
299
|
+
get :index, :params => { :version => 'v1', :format => "html", :resource => "resource-with-namespace" }
|
300
|
+
expect(response.body).to eq("resource-with-namespace.html cache")
|
301
|
+
|
302
|
+
get :index, :params => { :version => 'v1', :format => "html", :resource => "resource-with-namespace", :method => "method" }
|
303
|
+
expect(response.body).to eq("method.html cache")
|
304
|
+
end
|
297
305
|
end
|
298
306
|
|
299
|
-
|
307
|
+
context 'when the file does not exist' do
|
308
|
+
it 'returns a not found' do
|
309
|
+
get :index, :params => { :version => 'v3-does-not-exist' }
|
310
|
+
expect(response).to have_http_status(:not_found)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
context 'preventing path traversal' do
|
315
|
+
context 'when resource contains ..' do
|
316
|
+
it "returns a not found" do
|
317
|
+
get :index, :params => { :version => 'v1', :format => "html", :resource => "../resource-with-namespace", :method => "method" }
|
318
|
+
expect(response).to have_http_status(:not_found)
|
319
|
+
end
|
320
|
+
end
|
300
321
|
|
322
|
+
context 'when method contains ..' do
|
323
|
+
it "returns a not found" do
|
324
|
+
get :index, :params => { :version => 'v1', :format => "html", :resource => "resource-with-namespace", :method => "../method" }
|
325
|
+
expect(response).to have_http_status(:not_found)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
context 'when version contains ..' do
|
330
|
+
it "returns a not found" do
|
331
|
+
get :index, :params => { :version => '../v1', :format => "html", :resource => "resource-with-namespace", :method => "method" }
|
332
|
+
expect(response).to have_http_status(:not_found)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
context 'when format contains ..' do
|
337
|
+
it "returns a not found" do
|
338
|
+
get :index, :params => { :version => 'v1', :format => "../html", :resource => "resource-with-namespace", :method => "method" }
|
339
|
+
expect(response).to have_http_status(:not_found)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
end
|
301
345
|
|
302
346
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Apipie::Extractor::Collector do
|
6
|
+
let(:recorder) { described_class.new }
|
7
|
+
|
8
|
+
describe '#ignore_call?' do
|
9
|
+
subject { recorder.ignore_call?(record) }
|
10
|
+
|
11
|
+
let(:record) { { controller: controller, action: action } }
|
12
|
+
let(:controller) { ActionController::Base }
|
13
|
+
let(:action) { nil }
|
14
|
+
|
15
|
+
context 'when controller is nil' do
|
16
|
+
let(:controller) { nil }
|
17
|
+
|
18
|
+
it { is_expected.to be true }
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when controller is ignored' do
|
22
|
+
before do
|
23
|
+
allow(Apipie.configuration).to receive(:ignored_by_recorder).and_return(['ActionController::Bas'])
|
24
|
+
end
|
25
|
+
|
26
|
+
it { is_expected.to be true }
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when resource#method is ignored' do
|
30
|
+
let(:action) { 'ignored_action' }
|
31
|
+
|
32
|
+
before do
|
33
|
+
allow(Apipie.configuration).to receive(:ignored_by_recorder).and_return(['ActionController::Bas#ignored_action'])
|
34
|
+
end
|
35
|
+
|
36
|
+
it { is_expected.to be true }
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when controller is not an API controller' do
|
40
|
+
before do
|
41
|
+
allow(Apipie::Extractor).to receive(:controller_path).with('action_controller/base').and_return('foo')
|
42
|
+
allow(Apipie).to receive(:api_controllers_paths).and_return([])
|
43
|
+
end
|
44
|
+
|
45
|
+
it { is_expected.to be true }
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when controller is an API controller' do
|
49
|
+
before do
|
50
|
+
allow(Apipie::Extractor).to receive(:controller_path).with('action_controller/base').and_return('foo')
|
51
|
+
allow(Apipie).to receive(:api_controllers_paths).and_return(['foo'])
|
52
|
+
end
|
53
|
+
|
54
|
+
it { is_expected.to be_falsey }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -64,6 +64,19 @@ describe Apipie::Generator::Swagger::MethodDescription::ApiSchemaService do
|
|
64
64
|
it { is_expected.to include(*tags) }
|
65
65
|
end
|
66
66
|
|
67
|
+
context 'when Apipie.configuration.generator.swagger.skip_default_tags is enabled' do
|
68
|
+
before { Apipie.configuration.generator.swagger.skip_default_tags = true }
|
69
|
+
after { Apipie.configuration.generator.swagger.skip_default_tags = false }
|
70
|
+
|
71
|
+
it { is_expected.to be_empty }
|
72
|
+
|
73
|
+
context 'when tags are available' do
|
74
|
+
let(:tags) { ['Tag 1', 'Tag 2'] }
|
75
|
+
|
76
|
+
it { is_expected.to eq(tags) }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
67
80
|
context 'when Apipie.configuration.generator.swagger.include_warning_tags is enabled' do
|
68
81
|
before { Apipie.configuration.generator.swagger.include_warning_tags = true }
|
69
82
|
|
@@ -4,7 +4,7 @@ describe TestEngine::MemesController do
|
|
4
4
|
|
5
5
|
describe "#index" do
|
6
6
|
it "should have the full mounted path of engine" do
|
7
|
-
Apipie.routes_for_action(TestEngine::MemesController, :index, {}).first[:path].
|
7
|
+
expect(Apipie.routes_for_action(TestEngine::MemesController, :index, {}).first[:path]).to eq("/test/memes")
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|