apipie-rails 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|