lurker 0.6.1 → 0.6.2
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
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.hound.yml +62 -0
- data/.rubocop.yml +62 -0
- data/Gemfile +1 -1
- data/Rakefile +2 -268
- data/features/atom_persistent_within_the_same_type.feature +0 -2
- data/features/controller_nested_schema_scaffolding.feature +0 -1
- data/features/controller_schema_scaffolding.feature +0 -1
- data/features/html_generation.feature +0 -1
- data/features/minitest.feature +0 -2
- data/features/multidomain_support.feature +0 -1
- data/features/multitype_request_support.feature +0 -2
- data/features/partials.feature +0 -1
- data/features/request_nested_schema_scaffolding.feature +0 -1
- data/features/request_schema_scaffolding.feature +0 -1
- data/features/schema_suffixes.feature +0 -1
- data/features/schema_updating_within_test_suite.feature +37 -2
- data/features/test_endpoint.feature +0 -1
- data/lib/lurker.rb +5 -1
- data/lib/lurker/endpoint.rb +121 -176
- data/lib/lurker/endpoint/http_parameters.rb +77 -0
- data/lib/lurker/endpoint/response_codes.rb +42 -0
- data/lib/lurker/erb_schema_context.rb +8 -6
- data/lib/lurker/jaml_descriptor.rb +8 -1
- data/lib/lurker/json_schema_hash.rb +48 -0
- data/lib/lurker/presenters/base_presenter.rb +1 -2
- data/lib/lurker/presenters/endpoint_presenter.rb +17 -10
- data/lib/lurker/presenters/json_presenter.rb +6 -6
- data/lib/lurker/presenters/schema_presenter.rb +15 -14
- data/lib/lurker/presenters/service_presenter.rb +5 -6
- data/lib/lurker/rendering_controller.rb +0 -1
- data/lib/lurker/request.rb +3 -1
- data/lib/lurker/sandbox.rb +0 -1
- data/lib/lurker/schema_modifier.rb +4 -2
- data/lib/lurker/schema_modifier/atom.rb +14 -5
- data/lib/lurker/server.rb +4 -5
- data/lib/lurker/service.rb +3 -4
- data/lib/lurker/spec_helper/rspec.rb +15 -57
- data/lib/lurker/spy.rb +9 -5
- data/lib/lurker/templates/layouts/_sidemenu.html.erb +1 -1
- data/lib/lurker/templates/lurker/rendering/show.html.erb +5 -1
- data/lib/lurker/templates/public/application.css +2 -2
- data/lib/lurker/templates/stylesheets/docs.css +0 -1
- data/lib/lurker/utils.rb +18 -0
- data/lib/lurker/validator.rb +3 -6
- data/lib/lurker/version.rb +1 -1
- data/tasks/build.rake +57 -0
- data/tasks/deploy.rake +139 -0
- data/tasks/generate.rake +78 -0
- data/templates/generate_stuff.rb +4 -4
- data/templates/lurker_app.rb +1 -1
- metadata +9 -2
- metadata.gz.sig +0 -0
@@ -54,7 +54,6 @@ Feature: atom persistent within test suite
|
|
54
54
|
id: '100'
|
55
55
|
controller: api/v2/users
|
56
56
|
action: update
|
57
|
-
suffix: ''
|
58
57
|
"""
|
59
58
|
|
60
59
|
Scenario: json schema tests response parameters and keep atom unchanged using "users/update"
|
@@ -133,6 +132,5 @@ Feature: atom persistent within test suite
|
|
133
132
|
id: '100'
|
134
133
|
controller: api/v2/users
|
135
134
|
action: update
|
136
|
-
suffix: ''
|
137
135
|
|
138
136
|
"""
|
data/features/minitest.feature
CHANGED
@@ -61,7 +61,6 @@ Feature: minitest
|
|
61
61
|
controller: api/v1/repos
|
62
62
|
user_id: '1'
|
63
63
|
id: '1'
|
64
|
-
suffix: ''
|
65
64
|
|
66
65
|
"""
|
67
66
|
|
@@ -100,7 +99,6 @@ Feature: minitest
|
|
100
99
|
extensions:
|
101
100
|
path_info: "/api/v1/users/1"
|
102
101
|
method: PATCH
|
103
|
-
suffix: ''
|
104
102
|
path_params:
|
105
103
|
action: update
|
106
104
|
controller: api/v1/users
|
@@ -55,7 +55,6 @@ Feature: multitype request support
|
|
55
55
|
id: '1'
|
56
56
|
controller: api/v2/users
|
57
57
|
action: update
|
58
|
-
suffix: ''
|
59
58
|
"""
|
60
59
|
|
61
60
|
Scenario: json schema tests response parameters and update request parameters using "users/update"
|
@@ -134,6 +133,5 @@ Feature: multitype request support
|
|
134
133
|
id: '1'
|
135
134
|
controller: api/v2/users
|
136
135
|
action: update
|
137
|
-
suffix: ''
|
138
136
|
|
139
137
|
"""
|
data/features/partials.feature
CHANGED
@@ -26,6 +26,9 @@ Feature: schema updating within test suite
|
|
26
26
|
type: string
|
27
27
|
example: 'Bob'
|
28
28
|
responseCodes:
|
29
|
+
- status: 400
|
30
|
+
successful: true
|
31
|
+
description: ''
|
29
32
|
- status: 200
|
30
33
|
successful: true
|
31
34
|
description: ''
|
@@ -54,7 +57,37 @@ Feature: schema updating within test suite
|
|
54
57
|
id: '1'
|
55
58
|
controller: api/v2/users
|
56
59
|
action: update
|
57
|
-
|
60
|
+
"""
|
61
|
+
|
62
|
+
Scenario: json schema tests response parameters and request parameters and show errors from both using "users/update"
|
63
|
+
Given a file named "spec/controllers/api/v2/users_controller_blank_spec.rb" with:
|
64
|
+
"""ruby
|
65
|
+
require "spec_helper"
|
66
|
+
|
67
|
+
describe Api::V2::UsersController, :lurker do
|
68
|
+
render_views
|
69
|
+
|
70
|
+
let(:user) do
|
71
|
+
User.where(name: 'razum2um', surname: 'Unknown').first_or_create!
|
72
|
+
end
|
73
|
+
|
74
|
+
it "updates a user surname as string" do
|
75
|
+
patch :update, id: user.id, user: { name: '', surname: 'Marley' }
|
76
|
+
expect(response).not_to be_success
|
77
|
+
end
|
78
|
+
end
|
79
|
+
"""
|
80
|
+
|
81
|
+
When I run `bin/rspec spec/controllers/api/v2/users_controller_blank_spec.rb`
|
82
|
+
Then the output should contain failures:
|
83
|
+
"""
|
84
|
+
Lurker::ValidationError:
|
85
|
+
Request
|
86
|
+
The property '#/user' contains additional properties ["surname"]
|
87
|
+
Response
|
88
|
+
The property '#/' contains additional properties ["errors"]
|
89
|
+
|
90
|
+
1 example, 1 failure
|
58
91
|
"""
|
59
92
|
|
60
93
|
Scenario: json schema tests response parameters and update request parameters using "users/update"
|
@@ -105,6 +138,9 @@ Feature: schema updating within test suite
|
|
105
138
|
type: string
|
106
139
|
example: Marley
|
107
140
|
responseCodes:
|
141
|
+
- status: 400
|
142
|
+
successful: true
|
143
|
+
description: ''
|
108
144
|
- status: 200
|
109
145
|
successful: true
|
110
146
|
description: ''
|
@@ -133,6 +169,5 @@ Feature: schema updating within test suite
|
|
133
169
|
id: '1'
|
134
170
|
controller: api/v2/users
|
135
171
|
action: update
|
136
|
-
suffix: ''
|
137
172
|
|
138
173
|
"""
|
data/lib/lurker.rb
CHANGED
@@ -47,7 +47,9 @@ module Lurker
|
|
47
47
|
class UndocumentedResponseCode < ValidationError; end
|
48
48
|
end
|
49
49
|
|
50
|
+
require 'lurker/jaml_descriptor'
|
50
51
|
require 'lurker/schema'
|
52
|
+
require 'lurker/json_schema_hash'
|
51
53
|
require 'lurker/schema_modifier'
|
52
54
|
require 'lurker/schema_modifier/hash'
|
53
55
|
require 'lurker/schema_modifier/array'
|
@@ -55,10 +57,12 @@ require 'lurker/schema_modifier/atom'
|
|
55
57
|
require 'lurker/ref_object'
|
56
58
|
require 'lurker/erb_schema_context'
|
57
59
|
require 'lurker/service'
|
58
|
-
require 'lurker/jaml_descriptor'
|
59
60
|
require 'lurker/validator'
|
60
61
|
require 'lurker/validation_error'
|
62
|
+
require 'lurker/utils'
|
61
63
|
require 'lurker/endpoint'
|
64
|
+
require 'lurker/endpoint/response_codes'
|
65
|
+
require 'lurker/endpoint/http_parameters'
|
62
66
|
require 'lurker/rendering_controller'
|
63
67
|
require 'lurker/form_builder'
|
64
68
|
require 'lurker/presenters/json_presenter'
|
data/lib/lurker/endpoint.rb
CHANGED
@@ -4,221 +4,166 @@ require 'json-schema'
|
|
4
4
|
|
5
5
|
# Endpoints represent the schema for an API endpoint
|
6
6
|
# The #consume_* methods will raise exceptions if input differs from the schema
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
def indexed?
|
27
|
-
prefix.present? && description.present?
|
28
|
-
end
|
29
|
-
|
30
|
-
def consume!(request_params, response_params, status_code, successful=true)
|
31
|
-
consume_request(request_params, successful)
|
32
|
-
consume_response(response_params, status_code, successful)
|
33
|
-
raise_errors!
|
34
|
-
end
|
35
|
-
|
36
|
-
def consume_request(params, successful=true)
|
37
|
-
if successful
|
38
|
-
Lurker::SchemaModifier.merge!(request_parameters, stringify_keys(params))
|
7
|
+
module Lurker
|
8
|
+
class Endpoint
|
9
|
+
include Lurker::Utils
|
10
|
+
|
11
|
+
attr_reader :schema, :service, :endpoint_path, :extensions
|
12
|
+
attr_reader :request_parameters, :response_parameters, :response_codes
|
13
|
+
attr_accessor :errors
|
14
|
+
|
15
|
+
def initialize(endpoint_path, extensions = {}, service = Lurker::Service.default_service)
|
16
|
+
@endpoint_path = endpoint_path
|
17
|
+
@extensions = extensions
|
18
|
+
@service = service
|
19
|
+
@errors = []
|
20
|
+
@persisted = false
|
21
|
+
@schema = File.exist?(endpoint_path) ? load_schema : build_schema
|
22
|
+
|
23
|
+
initialize_schema_properties
|
39
24
|
end
|
40
|
-
end
|
41
25
|
|
42
|
-
|
43
|
-
|
26
|
+
def persist!
|
27
|
+
schema.ordered! unless persisted?
|
28
|
+
schema.write_to(endpoint_path)
|
44
29
|
|
45
|
-
|
46
|
-
Lurker::SchemaModifier.merge!(response_parameters, stringify_keys(params))
|
30
|
+
@persisted = true
|
47
31
|
end
|
48
32
|
|
49
|
-
|
50
|
-
|
51
|
-
"status" => status_code,
|
52
|
-
"successful" => successful,
|
53
|
-
"description" => ""
|
54
|
-
}
|
55
|
-
|
56
|
-
Lurker::SchemaModifier.append!(response_codes, response_code)
|
33
|
+
def indexed?
|
34
|
+
prefix.present? && description.present?
|
57
35
|
end
|
58
|
-
end
|
59
36
|
|
60
|
-
|
61
|
-
|
62
|
-
|
37
|
+
def consume!(request_params, response_params, status_code, successful = true)
|
38
|
+
consume_request(request_params, successful)
|
39
|
+
consume_response(response_params, status_code, successful)
|
63
40
|
|
64
|
-
|
65
|
-
|
66
|
-
gsub(service.service_dir, "").
|
67
|
-
match(/\/?(.*)[-\/][A-Z]+\.json(\.yml)?(\.erb)?$/)[1]
|
68
|
-
end
|
41
|
+
raise_errors!
|
42
|
+
end
|
69
43
|
|
70
|
-
|
44
|
+
def consume_request(params, successful = true)
|
45
|
+
request_parameters.validate(params) if persisted?
|
46
|
+
request_parameters.add(params) if successful
|
47
|
+
end
|
71
48
|
|
72
|
-
|
73
|
-
|
74
|
-
|
49
|
+
def consume_response(params, status_code, successful = true)
|
50
|
+
if persisted?
|
51
|
+
response_codes.validate!(status_code, successful)
|
52
|
+
response_parameters.validate(params) if successful
|
75
53
|
|
54
|
+
return
|
55
|
+
end
|
76
56
|
|
77
|
-
|
78
|
-
|
79
|
-
|
57
|
+
response_parameters.add(params) if successful
|
58
|
+
response_codes.add(status_code, successful) unless response_codes.exists?(
|
59
|
+
status_code, successful)
|
60
|
+
end
|
80
61
|
|
81
|
-
|
82
|
-
|
83
|
-
|
62
|
+
def verb
|
63
|
+
@verb ||= endpoint_path.match(/([A-Z]*)\.json(\.yml)?(\.erb)?$/)[1]
|
64
|
+
end
|
84
65
|
|
85
|
-
|
86
|
-
|
87
|
-
|
66
|
+
def path
|
67
|
+
@path ||= endpoint_path.
|
68
|
+
gsub(service.service_dir, "").
|
69
|
+
match(/\/?(.*)[-\/][A-Z]+\.json(\.yml)?(\.erb)?$/)[1]
|
70
|
+
end
|
88
71
|
|
89
|
-
|
90
|
-
(schema.extensions['query_params'] || {})
|
91
|
-
end
|
72
|
+
# properties
|
92
73
|
|
93
|
-
|
94
|
-
|
95
|
-
|
74
|
+
def deprecated?
|
75
|
+
@schema["deprecated"]
|
76
|
+
end
|
96
77
|
|
97
|
-
|
98
|
-
|
99
|
-
|
78
|
+
def prefix
|
79
|
+
@schema["prefix"]
|
80
|
+
end
|
100
81
|
|
101
|
-
|
102
|
-
|
103
|
-
|
82
|
+
def description
|
83
|
+
@schema["description"]
|
84
|
+
end
|
104
85
|
|
105
|
-
|
86
|
+
def url_params
|
87
|
+
(schema.extensions['path_params'] || {}).reject { |k, _| %w(action controller format).include? k }
|
88
|
+
end
|
106
89
|
|
107
|
-
|
108
|
-
|
109
|
-
|
90
|
+
def query_params
|
91
|
+
(schema.extensions['query_params'] || {})
|
92
|
+
end
|
110
93
|
|
111
|
-
|
112
|
-
@persisted = true
|
94
|
+
protected
|
113
95
|
|
114
|
-
|
115
|
-
|
116
|
-
stringify_keys(extensions)
|
117
|
-
)
|
118
|
-
end
|
96
|
+
def initialize_schema_properties
|
97
|
+
@response_codes = ResponseCodes.new(schema)
|
119
98
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
Lurker::Schema.new(
|
124
|
-
{
|
125
|
-
"prefix" => "",
|
126
|
-
"description" => "",
|
127
|
-
"responseCodes" => []
|
128
|
-
},
|
129
|
-
stringify_keys(extensions)
|
130
|
-
)
|
131
|
-
end
|
99
|
+
@response_parameters = HttpParameters.new(schema,
|
100
|
+
schema_key: 'responseParameters', schema_id: endpoint_path, human_name: 'Response')
|
132
101
|
|
133
|
-
|
134
|
-
|
135
|
-
context = Lurker::ErbSchemaContext.new
|
136
|
-
erb = ERB.new(IO.read(fname)).result(context.get_binding)
|
137
|
-
YAML.load(erb)
|
138
|
-
else
|
139
|
-
YAML.load_file(fname)
|
102
|
+
@request_parameters = HttpParameters.new(schema,
|
103
|
+
schema_key: 'requestParameters', schema_id: endpoint_path, human_name: 'Request')
|
140
104
|
end
|
141
|
-
end
|
142
105
|
|
143
|
-
|
144
|
-
|
145
|
-
schema['id'] = "file://#{endpoint_path}"
|
146
|
-
unless (_errors = Lurker::Validator.new(schema, stringify_keys(given_params), record_errors: true).validate).empty?
|
147
|
-
self.errors << prefix
|
148
|
-
_errors.each { |e| self.errors << "- #{e}" }
|
149
|
-
return false
|
106
|
+
def persisted?
|
107
|
+
!!@persisted
|
150
108
|
end
|
151
|
-
true
|
152
|
-
end
|
153
109
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
validate(response_parameters, params, 'Response')
|
162
|
-
else
|
163
|
-
true
|
110
|
+
def load_schema
|
111
|
+
@persisted = true
|
112
|
+
|
113
|
+
Lurker::Schema.new(
|
114
|
+
load_file(endpoint_path),
|
115
|
+
stringify_keys(extensions)
|
116
|
+
)
|
164
117
|
end
|
165
|
-
end
|
166
118
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
119
|
+
def build_schema
|
120
|
+
@persisted = false
|
121
|
+
|
122
|
+
Lurker::Schema.new(
|
123
|
+
{
|
124
|
+
"prefix" => "",
|
125
|
+
"description" => "",
|
126
|
+
"responseCodes" => []
|
127
|
+
},
|
128
|
+
stringify_keys(extensions)
|
129
|
+
)
|
172
130
|
end
|
173
|
-
end
|
174
131
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
132
|
+
def load_file(fname)
|
133
|
+
if fname.match(/\.erb$/)
|
134
|
+
context = Lurker::ErbSchemaContext.new
|
135
|
+
erb = ERB.new(IO.read(fname)).result(context.get_binding)
|
136
|
+
YAML.load(erb)
|
137
|
+
else
|
138
|
+
YAML.load_file(fname)
|
139
|
+
end
|
182
140
|
end
|
183
|
-
end
|
184
141
|
|
185
|
-
|
186
|
-
|
187
|
-
end
|
142
|
+
def raise_errors!
|
143
|
+
return if response_parameters.errors.empty?
|
188
144
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
copy = value.dup
|
194
|
-
if value["type"] == "object" || value.has_key?("properties")
|
195
|
-
copy["additionalProperties"] ||= false
|
196
|
-
end
|
197
|
-
value.each do |key, hash_val|
|
198
|
-
unless key == "additionalProperties"
|
199
|
-
copy[key] = set_additional_properties_false_on(hash_val)
|
200
|
-
end
|
145
|
+
errors = (request_parameters.errors | response_parameters.errors) * "\n"
|
146
|
+
exception = Lurker::ValidationError.new(word_wrap errors)
|
147
|
+
if (example = Lurker::Spy.current.block).respond_to?(:metadata) && (metadata = example.metadata).respond_to?(:location, true)
|
148
|
+
exception.set_backtrace [metadata.send(:location)]
|
201
149
|
end
|
202
|
-
|
203
|
-
elsif value.kind_of? Array
|
204
|
-
copy = value.map do |arr_val|
|
205
|
-
set_additional_properties_false_on(arr_val)
|
206
|
-
end
|
207
|
-
else
|
208
|
-
value
|
150
|
+
raise exception
|
209
151
|
end
|
210
|
-
end
|
211
152
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
153
|
+
def word_wrap(text)
|
154
|
+
# strip .json# | .json.yml# | .json.yml.erb#
|
155
|
+
text = text.reverse
|
156
|
+
text.gsub!(/(\n|^)#bre\./, "\nbre.")
|
157
|
+
text.gsub!(/(\n|^)#lmy\./, "\nlmy.")
|
158
|
+
text.gsub!(/(\n|^)#nosj\./, "\nnosj.")
|
159
|
+
text.strip!
|
160
|
+
text = text.reverse
|
161
|
+
|
162
|
+
text.gsub!(/\s+in schema/m, "\n in schema")
|
163
|
+
if defined?(Rails)
|
164
|
+
text.gsub!(/file:\/\/#{Rails.root}\//m, "")
|
218
165
|
end
|
219
|
-
|
220
|
-
when Array then obj.map { |v| stringify_keys(v) }
|
221
|
-
else obj
|
166
|
+
text
|
222
167
|
end
|
223
168
|
end
|
224
169
|
end
|